From: Kristian Høgsberg Date: Wed, 18 Jul 2012 15:39:05 +0000 (-0400) Subject: wcap: Just make wcap-decode dump YUV4MPEG2 X-Git-Tag: 0.95.0~38 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c12efd0aa7514eb6f6d22698db3a20f42bdf368a;p=platform%2Fupstream%2Fweston.git wcap: Just make wcap-decode dump YUV4MPEG2 Instead of having a custom fork of the vpxenc tool in weston, we can just dump raw YUV data in the YUV4MPEG2 format and feed that into the upstream vpxenc. This also works with theora_encoder and probably many other encoders. --- diff --git a/wcap/COPYING b/wcap/COPYING deleted file mode 100644 index 3d019b1..0000000 --- a/wcap/COPYING +++ /dev/null @@ -1,34 +0,0 @@ -The wcap-decode tool is based on the vpxenc tool from libvpx which is -under the following license: - -Copyright (c) 2010, The WebM Project authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of Google, nor the WebM Project, nor the names - of its contributors may be used to endorse or promote products - derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/wcap/EbmlIDs.h b/wcap/EbmlIDs.h deleted file mode 100644 index 3418e36..0000000 --- a/wcap/EbmlIDs.h +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2010 The WebM project authors. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. - - -#ifndef MKV_DEFS_HPP -#define MKV_DEFS_HPP 1 - -//Commenting out values not available in webm, but available in matroska - -enum mkv -{ - EBML = 0x1A45DFA3, - EBMLVersion = 0x4286, - EBMLReadVersion = 0x42F7, - EBMLMaxIDLength = 0x42F2, - EBMLMaxSizeLength = 0x42F3, - DocType = 0x4282, - DocTypeVersion = 0x4287, - DocTypeReadVersion = 0x4285, -// CRC_32 = 0xBF, - Void = 0xEC, - SignatureSlot = 0x1B538667, - SignatureAlgo = 0x7E8A, - SignatureHash = 0x7E9A, - SignaturePublicKey = 0x7EA5, - Signature = 0x7EB5, - SignatureElements = 0x7E5B, - SignatureElementList = 0x7E7B, - SignedElement = 0x6532, - //segment - Segment = 0x18538067, - //Meta Seek Information - SeekHead = 0x114D9B74, - Seek = 0x4DBB, - SeekID = 0x53AB, - SeekPosition = 0x53AC, - //Segment Information - Info = 0x1549A966, -// SegmentUID = 0x73A4, -// SegmentFilename = 0x7384, -// PrevUID = 0x3CB923, -// PrevFilename = 0x3C83AB, -// NextUID = 0x3EB923, -// NextFilename = 0x3E83BB, -// SegmentFamily = 0x4444, -// ChapterTranslate = 0x6924, -// ChapterTranslateEditionUID = 0x69FC, -// ChapterTranslateCodec = 0x69BF, -// ChapterTranslateID = 0x69A5, - TimecodeScale = 0x2AD7B1, - Segment_Duration = 0x4489, - DateUTC = 0x4461, -// Title = 0x7BA9, - MuxingApp = 0x4D80, - WritingApp = 0x5741, - //Cluster - Cluster = 0x1F43B675, - Timecode = 0xE7, -// SilentTracks = 0x5854, -// SilentTrackNumber = 0x58D7, -// Position = 0xA7, - PrevSize = 0xAB, - BlockGroup = 0xA0, - Block = 0xA1, -// BlockVirtual = 0xA2, -// BlockAdditions = 0x75A1, -// BlockMore = 0xA6, -// BlockAddID = 0xEE, -// BlockAdditional = 0xA5, - BlockDuration = 0x9B, -// ReferencePriority = 0xFA, - ReferenceBlock = 0xFB, -// ReferenceVirtual = 0xFD, -// CodecState = 0xA4, -// Slices = 0x8E, -// TimeSlice = 0xE8, - LaceNumber = 0xCC, -// FrameNumber = 0xCD, -// BlockAdditionID = 0xCB, -// MkvDelay = 0xCE, -// Cluster_Duration = 0xCF, - SimpleBlock = 0xA3, -// EncryptedBlock = 0xAF, - //Track - Tracks = 0x1654AE6B, - TrackEntry = 0xAE, - TrackNumber = 0xD7, - TrackUID = 0x73C5, - TrackType = 0x83, - FlagEnabled = 0xB9, - FlagDefault = 0x88, - FlagForced = 0x55AA, - FlagLacing = 0x9C, -// MinCache = 0x6DE7, -// MaxCache = 0x6DF8, - DefaultDuration = 0x23E383, -// TrackTimecodeScale = 0x23314F, -// TrackOffset = 0x537F, -// MaxBlockAdditionID = 0x55EE, - Name = 0x536E, - Language = 0x22B59C, - CodecID = 0x86, - CodecPrivate = 0x63A2, - CodecName = 0x258688, -// AttachmentLink = 0x7446, -// CodecSettings = 0x3A9697, -// CodecInfoURL = 0x3B4040, -// CodecDownloadURL = 0x26B240, -// CodecDecodeAll = 0xAA, -// TrackOverlay = 0x6FAB, -// TrackTranslate = 0x6624, -// TrackTranslateEditionUID = 0x66FC, -// TrackTranslateCodec = 0x66BF, -// TrackTranslateTrackID = 0x66A5, - //video - Video = 0xE0, - FlagInterlaced = 0x9A, - StereoMode = 0x53B8, - PixelWidth = 0xB0, - PixelHeight = 0xBA, - PixelCropBottom = 0x54AA, - PixelCropTop = 0x54BB, - PixelCropLeft = 0x54CC, - PixelCropRight = 0x54DD, - DisplayWidth = 0x54B0, - DisplayHeight = 0x54BA, - DisplayUnit = 0x54B2, - AspectRatioType = 0x54B3, -// ColourSpace = 0x2EB524, -// GammaValue = 0x2FB523, - FrameRate = 0x2383E3, - //end video - //audio - Audio = 0xE1, - SamplingFrequency = 0xB5, - OutputSamplingFrequency = 0x78B5, - Channels = 0x9F, -// ChannelPositions = 0x7D7B, - BitDepth = 0x6264, - //end audio - //content encoding -// ContentEncodings = 0x6d80, -// ContentEncoding = 0x6240, -// ContentEncodingOrder = 0x5031, -// ContentEncodingScope = 0x5032, -// ContentEncodingType = 0x5033, -// ContentCompression = 0x5034, -// ContentCompAlgo = 0x4254, -// ContentCompSettings = 0x4255, -// ContentEncryption = 0x5035, -// ContentEncAlgo = 0x47e1, -// ContentEncKeyID = 0x47e2, -// ContentSignature = 0x47e3, -// ContentSigKeyID = 0x47e4, -// ContentSigAlgo = 0x47e5, -// ContentSigHashAlgo = 0x47e6, - //end content encoding - //Cueing Data - Cues = 0x1C53BB6B, - CuePoint = 0xBB, - CueTime = 0xB3, - CueTrackPositions = 0xB7, - CueTrack = 0xF7, - CueClusterPosition = 0xF1, - CueBlockNumber = 0x5378, -// CueCodecState = 0xEA, -// CueReference = 0xDB, -// CueRefTime = 0x96, -// CueRefCluster = 0x97, -// CueRefNumber = 0x535F, -// CueRefCodecState = 0xEB, - //Attachment -// Attachments = 0x1941A469, -// AttachedFile = 0x61A7, -// FileDescription = 0x467E, -// FileName = 0x466E, -// FileMimeType = 0x4660, -// FileData = 0x465C, -// FileUID = 0x46AE, -// FileReferral = 0x4675, - //Chapters -// Chapters = 0x1043A770, -// EditionEntry = 0x45B9, -// EditionUID = 0x45BC, -// EditionFlagHidden = 0x45BD, -// EditionFlagDefault = 0x45DB, -// EditionFlagOrdered = 0x45DD, -// ChapterAtom = 0xB6, -// ChapterUID = 0x73C4, -// ChapterTimeStart = 0x91, -// ChapterTimeEnd = 0x92, -// ChapterFlagHidden = 0x98, -// ChapterFlagEnabled = 0x4598, -// ChapterSegmentUID = 0x6E67, -// ChapterSegmentEditionUID = 0x6EBC, -// ChapterPhysicalEquiv = 0x63C3, -// ChapterTrack = 0x8F, -// ChapterTrackNumber = 0x89, -// ChapterDisplay = 0x80, -// ChapString = 0x85, -// ChapLanguage = 0x437C, -// ChapCountry = 0x437E, -// ChapProcess = 0x6944, -// ChapProcessCodecID = 0x6955, -// ChapProcessPrivate = 0x450D, -// ChapProcessCommand = 0x6911, -// ChapProcessTime = 0x6922, -// ChapProcessData = 0x6933, - //Tagging -// Tags = 0x1254C367, -// Tag = 0x7373, -// Targets = 0x63C0, -// TargetTypeValue = 0x68CA, -// TargetType = 0x63CA, -// Tagging_TrackUID = 0x63C5, -// Tagging_EditionUID = 0x63C9, -// Tagging_ChapterUID = 0x63C4, -// AttachmentUID = 0x63C6, -// SimpleTag = 0x67C8, -// TagName = 0x45A3, -// TagLanguage = 0x447A, -// TagDefault = 0x4484, -// TagString = 0x4487, -// TagBinary = 0x4485, -}; -#endif diff --git a/wcap/EbmlWriter.c b/wcap/EbmlWriter.c deleted file mode 100644 index fbf2c66..0000000 --- a/wcap/EbmlWriter.c +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2010 The WebM project authors. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. - - -#include "EbmlWriter.h" -#include -#include -#include -#include -#if defined(_MSC_VER) -#define LITERALU64(n) n -#else -#define LITERALU64(n) n##LLU -#endif - -void Ebml_WriteLen(EbmlGlobal *glob, long long val) -{ - //TODO check and make sure we are not > than 0x0100000000000000LLU - unsigned char size = 8; //size in bytes to output - unsigned long long minVal = LITERALU64(0x00000000000000ff); //mask to compare for byte size - - for (size = 1; size < 8; size ++) - { - if (val < minVal) - break; - - minVal = (minVal << 7); - } - - val |= (LITERALU64(0x000000000000080) << ((size - 1) * 7)); - - Ebml_Serialize(glob, (void *) &val, sizeof(val), size); -} - -void Ebml_WriteString(EbmlGlobal *glob, const char *str) -{ - const size_t size_ = strlen(str); - const unsigned long long size = size_; - Ebml_WriteLen(glob, size); - //TODO: it's not clear from the spec whether the nul terminator - //should be serialized too. For now we omit the null terminator. - Ebml_Write(glob, str, size); -} - -void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr) -{ - const size_t strlen = wcslen(wstr); - - //TODO: it's not clear from the spec whether the nul terminator - //should be serialized too. For now we include it. - const unsigned long long size = strlen; - - Ebml_WriteLen(glob, size); - Ebml_Write(glob, wstr, size); -} - -void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id) -{ - int len; - - if (class_id >= 0x01000000) - len = 4; - else if (class_id >= 0x00010000) - len = 3; - else if (class_id >= 0x00000100) - len = 2; - else - len = 1; - - Ebml_Serialize(glob, (void *)&class_id, sizeof(class_id), len); -} - -void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) -{ - unsigned char sizeSerialized = 8 | 0x80; - Ebml_WriteID(glob, class_id); - Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); - Ebml_Serialize(glob, &ui, sizeof(ui), 8); -} - -void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui) -{ - unsigned char size = 8; //size in bytes to output - unsigned char sizeSerialized = 0; - unsigned long minVal; - - Ebml_WriteID(glob, class_id); - minVal = 0x7fLU; //mask to compare for byte size - - for (size = 1; size < 4; size ++) - { - if (ui < minVal) - { - break; - } - - minVal <<= 7; - } - - sizeSerialized = 0x80 | size; - Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); - Ebml_Serialize(glob, &ui, sizeof(ui), size); -} -//TODO: perhaps this is a poor name for this id serializer helper function -void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long bin) -{ - int size; - for (size=4; size > 1; size--) - { - if (bin & 0x000000ff << ((size-1) * 8)) - break; - } - Ebml_WriteID(glob, class_id); - Ebml_WriteLen(glob, size); - Ebml_WriteID(glob, bin); -} - -void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d) -{ - unsigned char len = 0x88; - - Ebml_WriteID(glob, class_id); - Ebml_Serialize(glob, &len, sizeof(len), 1); - Ebml_Serialize(glob, &d, sizeof(d), 8); -} - -void Ebml_WriteSigned16(EbmlGlobal *glob, short val) -{ - signed long out = ((val & 0x003FFFFF) | 0x00200000) << 8; - Ebml_Serialize(glob, &out, sizeof(out), 3); -} - -void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s) -{ - Ebml_WriteID(glob, class_id); - Ebml_WriteString(glob, s); -} - -void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s) -{ - Ebml_WriteID(glob, class_id); - Ebml_WriteUTF8(glob, s); -} - -void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length) -{ - Ebml_WriteID(glob, class_id); - Ebml_WriteLen(glob, data_length); - Ebml_Write(glob, data, data_length); -} - -void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize) -{ - unsigned char tmp = 0; - unsigned long i = 0; - - Ebml_WriteID(glob, 0xEC); - Ebml_WriteLen(glob, vSize); - - for (i = 0; i < vSize; i++) - { - Ebml_Write(glob, &tmp, 1); - } -} - -//TODO Serialize Date diff --git a/wcap/EbmlWriter.h b/wcap/EbmlWriter.h deleted file mode 100644 index 324c9bc..0000000 --- a/wcap/EbmlWriter.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef EBMLWRITER_HPP -#define EBMLWRITER_HPP - -// Copyright (c) 2010 The WebM project authors. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. - -//note: you must define write and serialize functions as well as your own EBML_GLOBAL -//These functions MUST be implemented -#include -#include "vpx/vpx_integer.h" - -typedef struct EbmlGlobal EbmlGlobal; -void Ebml_Serialize(EbmlGlobal *glob, const void *, int, unsigned long); -void Ebml_Write(EbmlGlobal *glob, const void *, unsigned long); -///// - - -void Ebml_WriteLen(EbmlGlobal *glob, long long val); -void Ebml_WriteString(EbmlGlobal *glob, const char *str); -void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr); -void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id); -void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui); -void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui); -void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long ui); -void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d); -//TODO make this more generic to signed -void Ebml_WriteSigned16(EbmlGlobal *glob, short val); -void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s); -void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s); -void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length); -void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize); -//TODO need date function -#endif diff --git a/wcap/Makefile.am b/wcap/Makefile.am index 187c5c3..da0ba90 100644 --- a/wcap/Makefile.am +++ b/wcap/Makefile.am @@ -1,31 +1,9 @@ -bin_PROGRAMS = wcap-decode wcap-snapshot +bin_PROGRAMS = wcap-decode wcap_decode_SOURCES = \ - args.c \ - args.h \ - EbmlIDs.h \ - EbmlWriter.c \ - EbmlWriter.h \ - mem_ops_aligned.h \ - mem_ops.h \ - tools_common.c \ - tools_common.h \ - vpxenc.c \ - vpx_timer.h \ - vpx_config.h \ - y4minput.c \ - y4minput.h \ + main.c \ wcap-decode.c \ wcap-decode.h -wcap_decode_CPPFLAGS = -DCONFIG_VP8_ENCODER=1 wcap_decode_CFLAGS = $(WCAP_CFLAGS) wcap_decode_LDADD = $(WCAP_LIBS) - -wcap_snapshot_SOURCES = \ - wcap-snapshot.c \ - wcap-decode.c \ - wcap-decode.h - -wcap_snapshot_CFLAGS = $(WCAP_CFLAGS) -wcap_snapshot_LDADD = $(WCAP_LIBS) diff --git a/wcap/README b/wcap/README index dfbddf1..666a708 100644 --- a/wcap/README +++ b/wcap/README @@ -9,18 +9,18 @@ something actually changes. Recording in Weston is started by pressing MOD+R and stopped by pressing MOD+R again. Currently this leaves a capture.wcap file in the cwd of the weston process. The file format is documented below -and Weston comes with two tools to convert the wcap file into -something more usable: +and Weston comes with the wcap-decode tool to convert the wcap file +into something more usable: - - wcap-snapshot; a simple tool that will extract a given frame from - the capture as a png. This will produce a lossless screenshot, - which is useful if you're trying to screenshot a brief glitch or - something like that that's hard to capture with the screenshot tool. + - Extract single or all frames as individual png files. This will + produce a lossless screenshot, which is useful if you're trying to + screenshot a brief glitch or something like that that's hard to + capture with the screenshot tool. - wcap-snapshot takes a wcap file as its first argument. Without - anything else, it will show the screen size and number of frames in - the file. With an integer second argument, it will extract that - frame as a png: + wcap-decode takes a number of options and a wcap file as its + arguments. Without anything else, it will show the screen size and + number of frames in the file. Pass --frame= to extract a + single frame or pass --all to extract all frames as png files: [krh@minato weston]$ wcap-snapshot capture.wcap wcap file: size 1024x640, 176 frames @@ -28,23 +28,23 @@ something more usable: wrote wcap-frame-20.png wcap file: size 1024x640, 176 frames - - wcap-decode; this is a copy of the vpxenc tool from the libvpx - repository, with wcap input file support added. The tool can - encode a wcap file into a webm video (http://www.webmproject.org/). - The command line arguments are identical to what the vpxenc tool - takes and wcap-decode will print them if run without any arguments. + - Decode and the wcap file and dump it as a YUV4MPEG2 stream on + stdout. This format is compatible with most video encoders and can + be piped directly into a command line encoder such as vpxenc (part + of libvpx, encodes to a webm file) or theora_encode (part of + libtheora, encodes to a ogg theora file). - The minimal command line requires a webm output file and a wcap - input file: + Using vpxenc to encode a webm file would look something like this: - [krh@minato weston]$ wcap-decode -o foo.webm capture.wcap + [krh@minato weston]$ wcap-decode --yuv4mpeg2 ../capture.wcap | + vpxenc --target-bitrate=1024 --best -t 4 -o foo.webm - - but it's possible to select target bitrate and output framerate and - it's typically useful to pass -t 4 to let the tool use multiple - threads: + where we select target bitrate, pass -t 4 to let vpxenc use + multiple threads. To encode to Ogg Theora a command line like this + works: - [krh@minato weston]$ wcap-decode --target-bitrate=1024 \ - --best -t 4 -o foo.webm capture.wcap --fps=10/1 + [krh@minato weston]$ wcap-decode ../capture.wcap --yuv4mpeg2 | + theora_encode - -o cap.ogv WCAP File format diff --git a/wcap/args.c b/wcap/args.c deleted file mode 100644 index 37ba778..0000000 --- a/wcap/args.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#include -#include -#include -#include "args.h" - -#ifdef _MSC_VER -#define snprintf _snprintf -#endif - -#if defined(__GNUC__) && __GNUC__ -extern void die(const char *fmt, ...) __attribute__((noreturn)); -#else -extern void die(const char *fmt, ...); -#endif - - -struct arg arg_init(char **argv) -{ - struct arg a; - - a.argv = argv; - a.argv_step = 1; - a.name = NULL; - a.val = NULL; - a.def = NULL; - return a; -} - -int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) -{ - struct arg arg; - - if (!argv[0] || argv[0][0] != '-') - return 0; - - arg = arg_init(argv); - - if (def->short_name - && strlen(arg.argv[0]) == strlen(def->short_name) + 1 - && !strcmp(arg.argv[0] + 1, def->short_name)) - { - - arg.name = arg.argv[0] + 1; - arg.val = def->has_val ? arg.argv[1] : NULL; - arg.argv_step = def->has_val ? 2 : 1; - } - else if (def->long_name) - { - const size_t name_len = strlen(def->long_name); - - if (strlen(arg.argv[0]) >= name_len + 2 - && arg.argv[0][1] == '-' - && !strncmp(arg.argv[0] + 2, def->long_name, name_len) - && (arg.argv[0][name_len+2] == '=' - || arg.argv[0][name_len+2] == '\0')) - { - - arg.name = arg.argv[0] + 2; - arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL; - arg.argv_step = 1; - } - } - - if (arg.name && !arg.val && def->has_val) - die("Error: option %s requires argument.\n", arg.name); - - if (arg.name && arg.val && !def->has_val) - die("Error: option %s requires no argument.\n", arg.name); - - if (arg.name - && (arg.val || !def->has_val)) - { - arg.def = def; - *arg_ = arg; - return 1; - } - - return 0; -} - - -const char *arg_next(struct arg *arg) -{ - if (arg->argv[0]) - arg->argv += arg->argv_step; - - return *arg->argv; -} - - -char **argv_dup(int argc, const char **argv) -{ - char **new_argv = malloc((argc + 1) * sizeof(*argv)); - - memcpy(new_argv, argv, argc * sizeof(*argv)); - new_argv[argc] = NULL; - return new_argv; -} - - -void arg_show_usage(FILE *fp, const struct arg_def *const *defs) -{ - char option_text[40] = {0}; - - for (; *defs; defs++) - { - const struct arg_def *def = *defs; - char *short_val = def->has_val ? " " : ""; - char *long_val = def->has_val ? "=" : ""; - - if (def->short_name && def->long_name) - { - char *comma = def->has_val ? "," : ", "; - - snprintf(option_text, 37, "-%s%s%s --%s%6s", - def->short_name, short_val, comma, - def->long_name, long_val); - } - else if (def->short_name) - snprintf(option_text, 37, "-%s%s", - def->short_name, short_val); - else if (def->long_name) - snprintf(option_text, 37, " --%s%s", - def->long_name, long_val); - - fprintf(fp, " %-37s\t%s\n", option_text, def->desc); - - if(def->enums) - { - const struct arg_enum_list *listptr; - - fprintf(fp, " %-37s\t ", ""); - - for(listptr = def->enums; listptr->name; listptr++) - fprintf(fp, "%s%s", listptr->name, - listptr[1].name ? ", " : "\n"); - } - } -} - - -unsigned int arg_parse_uint(const struct arg *arg) -{ - long int rawval; - char *endptr; - - rawval = strtol(arg->val, &endptr, 10); - - if (arg->val[0] != '\0' && endptr[0] == '\0') - { - if (rawval >= 0 && rawval <= UINT_MAX) - return rawval; - - die("Option %s: Value %ld out of range for unsigned int\n", - arg->name, rawval); - } - - die("Option %s: Invalid character '%c'\n", arg->name, *endptr); - return 0; -} - - -int arg_parse_int(const struct arg *arg) -{ - long int rawval; - char *endptr; - - rawval = strtol(arg->val, &endptr, 10); - - if (arg->val[0] != '\0' && endptr[0] == '\0') - { - if (rawval >= INT_MIN && rawval <= INT_MAX) - return rawval; - - die("Option %s: Value %ld out of range for signed int\n", - arg->name, rawval); - } - - die("Option %s: Invalid character '%c'\n", arg->name, *endptr); - return 0; -} - - -struct vpx_rational -{ - int num; /**< fraction numerator */ - int den; /**< fraction denominator */ -}; -struct vpx_rational arg_parse_rational(const struct arg *arg) -{ - long int rawval; - char *endptr; - struct vpx_rational rat; - - /* parse numerator */ - rawval = strtol(arg->val, &endptr, 10); - - if (arg->val[0] != '\0' && endptr[0] == '/') - { - if (rawval >= INT_MIN && rawval <= INT_MAX) - rat.num = rawval; - else die("Option %s: Value %ld out of range for signed int\n", - arg->name, rawval); - } - else die("Option %s: Expected / at '%c'\n", arg->name, *endptr); - - /* parse denominator */ - rawval = strtol(endptr + 1, &endptr, 10); - - if (arg->val[0] != '\0' && endptr[0] == '\0') - { - if (rawval >= INT_MIN && rawval <= INT_MAX) - rat.den = rawval; - else die("Option %s: Value %ld out of range for signed int\n", - arg->name, rawval); - } - else die("Option %s: Invalid character '%c'\n", arg->name, *endptr); - - return rat; -} - - -int arg_parse_enum(const struct arg *arg) -{ - const struct arg_enum_list *listptr; - long int rawval; - char *endptr; - - /* First see if the value can be parsed as a raw value */ - rawval = strtol(arg->val, &endptr, 10); - if (arg->val[0] != '\0' && endptr[0] == '\0') - { - /* Got a raw value, make sure it's valid */ - for(listptr = arg->def->enums; listptr->name; listptr++) - if(listptr->val == rawval) - return rawval; - } - - /* Next see if it can be parsed as a string */ - for(listptr = arg->def->enums; listptr->name; listptr++) - if(!strcmp(arg->val, listptr->name)) - return listptr->val; - - die("Option %s: Invalid value '%s'\n", arg->name, arg->val); - return 0; -} - - -int arg_parse_enum_or_int(const struct arg *arg) -{ - if(arg->def->enums) - return arg_parse_enum(arg); - return arg_parse_int(arg); -} diff --git a/wcap/args.h b/wcap/args.h deleted file mode 100644 index 7963fa6..0000000 --- a/wcap/args.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#ifndef ARGS_H -#define ARGS_H -#include - -struct arg -{ - char **argv; - const char *name; - const char *val; - unsigned int argv_step; - const struct arg_def *def; -}; - -struct arg_enum_list -{ - const char *name; - int val; -}; -#define ARG_ENUM_LIST_END {0} - -typedef struct arg_def -{ - const char *short_name; - const char *long_name; - int has_val; - const char *desc; - const struct arg_enum_list *enums; -} arg_def_t; -#define ARG_DEF(s,l,v,d) {s,l,v,d, NULL} -#define ARG_DEF_ENUM(s,l,v,d,e) {s,l,v,d,e} -#define ARG_DEF_LIST_END {0} - -struct arg arg_init(char **argv); -int arg_match(struct arg *arg_, const struct arg_def *def, char **argv); -const char *arg_next(struct arg *arg); -void arg_show_usage(FILE *fp, const struct arg_def *const *defs); -char **argv_dup(int argc, const char **argv); - -unsigned int arg_parse_uint(const struct arg *arg); -int arg_parse_int(const struct arg *arg); -struct vpx_rational arg_parse_rational(const struct arg *arg); -int arg_parse_enum_or_int(const struct arg *arg); -#endif diff --git a/wcap/main.c b/wcap/main.c new file mode 100644 index 0000000..bdbc8cb --- /dev/null +++ b/wcap/main.c @@ -0,0 +1,240 @@ +/* + * Copyright © 2012 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "wcap-decode.h" + +static void +write_png(struct wcap_decoder *decoder, const char *filename) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data((unsigned char *) decoder->frame, + CAIRO_FORMAT_ARGB32, + decoder->width, + decoder->height, + decoder->width * 4); + cairo_surface_write_to_png(surface, filename); + cairo_surface_destroy(surface); +} + +static inline int +rgb_to_yuv(uint32_t format, uint32_t p, int *u, int *v) +{ + int r, g, b, y; + + switch (format) { + case WCAP_FORMAT_XRGB8888: + r = (p >> 16) & 0xff; + g = (p >> 8) & 0xff; + b = (p >> 0) & 0xff; + break; + case WCAP_FORMAT_XBGR8888: + r = (p >> 0) & 0xff; + g = (p >> 8) & 0xff; + b = (p >> 16) & 0xff; + break; + } + + y = (19595 * r + 38469 * g + 7472 * b) >> 16; + if (y > 255) + y = 255; + + *u += 46727 * (r - y); + *v += 36962 * (b - y); + + return y; +} + +static inline +int clamp_uv(int u) +{ + int clamp = (u >> 18) + 128; + + if (clamp < 0) + return 0; + else if (clamp > 255) + return 255; + else + return clamp; +} + +static void +convert_to_yv12(struct wcap_decoder *decoder, unsigned char *out) +{ + unsigned char *y1, *y2, *u, *v; + uint32_t *p1, *p2, *end; + int i, u_accum, v_accum, stride0, stride1; + uint32_t format = decoder->format; + + stride0 = decoder->width; + stride1 = decoder->width / 2; + for (i = 0; i < decoder->height; i += 2) { + y1 = out + stride0 * i; + y2 = y1 + stride0; + v = out + stride0 * decoder->height + stride1 * i / 2; + u = v + stride1 * decoder->height / 2; + p1 = decoder->frame + decoder->width * i; + p2 = p1 + decoder->width; + end = p1 + decoder->width; + + while (p1 < end) { + u_accum = 0; + v_accum = 0; + y1[0] = rgb_to_yuv(format, p1[0], &u_accum, &v_accum); + y1[1] = rgb_to_yuv(format, p1[1], &u_accum, &v_accum); + y2[0] = rgb_to_yuv(format, p2[0], &u_accum, &v_accum); + y2[1] = rgb_to_yuv(format, p2[1], &u_accum, &v_accum); + u[0] = clamp_uv(u_accum); + v[0] = clamp_uv(v_accum); + + y1 += 2; + p1 += 2; + y2 += 2; + p2 += 2; + u++; + v++; + } + } +} + +static void +output_yuv_frame(struct wcap_decoder *decoder) +{ + static char *out; + int size; + + size = decoder->width * decoder->height * 3 / 2; + if (out == NULL) + out = malloc(size); + + convert_to_yv12(decoder, out); + printf("FRAME\n"); + fwrite(out, 1, size, stdout); +} + +static void +usage(int exit_code) +{ + fprintf(stderr, "usage: wcap-snapshot " + "[--help] [--yuv4mpeg2] [--frame=] [--all] \n" + "\t[--rate=] \n\n" + "\t--help\t\t\tthis help text\n" + "\t--yuv2mpeg4\t\tdump wcap file in yuv4mpeg format\n" + "\t--frame=\t\twrite out the given frame number as png\n" + "\t--all\t\t\twrite all frames as pngs\n" + "\t--rate=\treplay frame rate for yuv4mpeg2,\n" + "\t\t\t\tspecified as an integer fraction\n\n"); + + exit(exit_code); +} + +int main(int argc, char *argv[]) +{ + struct wcap_decoder *decoder; + int i, j, output_frame = -1, yuv4mpeg2 = 0, all = 0, has_frame; + int num = 30, denom = 1; + char filename[200]; + uint32_t msecs, frame_time, *frame, frame_size; + + for (i = 1, j = 1; i < argc; i++) { + if (strcmp(argv[i], "--yuv4mpeg2") == 0) { + yuv4mpeg2 = 1; + } else if (strcmp(argv[i], "--help") == 0) { + usage(EXIT_SUCCESS); + } else if (strcmp(argv[i], "--all") == 0) { + all = 1; + } else if (sscanf(argv[i], "--frame=%d", &output_frame) == 1) { + ; + } else if (sscanf(argv[i], "--rate=%d", &num) == 1) { + ; + } else if (sscanf(argv[i], "--rate=%d:%d", &num, &denom) == 2) { + ; + } else if (strcmp(argv[i], "--") == 0) { + break; + } else if (argv[i][0] == '-') { + fprintf(stderr, + "unknown option or invalid argument: %s\n", argv[i]); + usage(EXIT_FAILURE); + } else { + argv[j++] = argv[i]; + } + } + argc = j; + + if (argc != 2) + usage(EXIT_FAILURE); + if (denom == 0) { + fprintf(stderr, "invalid rate, denom can not be 0\n"); + exit(EXIT_FAILURE); + } + + decoder = wcap_decoder_create(argv[1]); + + if (yuv4mpeg2) { + printf("YUV4MPEG2 C420jpeg W%d H%d F%d:%d Ip A0:0\n", + decoder->width, decoder->height, num, denom); + fflush(stdout); + } + + i = 0; + has_frame = wcap_decoder_get_frame(decoder); + msecs = decoder->msecs; + frame_time = 1000 * denom / num; + frame_size = decoder->width * decoder->height * 4; + frame = malloc(frame_size); + while (has_frame) { + if (decoder->msecs >= msecs) + memcpy(frame, decoder->frame, frame_size); + if (all || i == output_frame) { + snprintf(filename, sizeof filename, + "wcap-frame-%d.png", i); + write_png(decoder, filename); + fprintf(stderr, "wrote %s\n", filename); + } + if (yuv4mpeg2) + output_yuv_frame(decoder); + i++; + msecs += frame_time; + while (decoder->msecs < msecs && has_frame) + has_frame = wcap_decoder_get_frame(decoder); + } + + fprintf(stderr, "wcap file: size %dx%d, %d frames\n", + decoder->width, decoder->height, i); + + wcap_decoder_destroy(decoder); + + return EXIT_SUCCESS; +} diff --git a/wcap/mem_ops.h b/wcap/mem_ops.h deleted file mode 100644 index 0e52368..0000000 --- a/wcap/mem_ops.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -/* \file - * \brief Provides portable memory access primitives - * - * This function provides portable primitives for getting and setting of - * signed and unsigned integers in 16, 24, and 32 bit sizes. The operations - * can be performed on unaligned data regardless of hardware support for - * unaligned accesses. - * - * The type used to pass the integral values may be changed by defining - * MEM_VALUE_T with the appropriate type. The type given must be an integral - * numeric type. - * - * The actual functions instantiated have the MEM_VALUE_T type name pasted - * on to the symbol name. This allows the developer to instantiate these - * operations for multiple types within the same translation unit. This is - * of somewhat questionable utility, but the capability exists nonetheless. - * Users not making use of this functionality should call the functions - * without the type name appended, and the preprocessor will take care of - * it. - * - * NOTE: This code is not supported on platforms where char > 1 octet ATM. - */ - -#ifndef MAU_T -/* Minimum Access Unit for this target */ -#define MAU_T unsigned char -#endif - -#ifndef MEM_VALUE_T -#define MEM_VALUE_T int -#endif - -#undef MEM_VALUE_T_SZ_BITS -#define MEM_VALUE_T_SZ_BITS (sizeof(MEM_VALUE_T) << 3) - -#undef mem_ops_wrap_symbol -#define mem_ops_wrap_symbol(fn) mem_ops_wrap_symbol2(fn, MEM_VALUE_T) -#undef mem_ops_wrap_symbol2 -#define mem_ops_wrap_symbol2(fn,typ) mem_ops_wrap_symbol3(fn,typ) -#undef mem_ops_wrap_symbol3 -#define mem_ops_wrap_symbol3(fn,typ) fn##_as_##typ - -/* - * Include aligned access routines - */ -#define INCLUDED_BY_MEM_OPS_H -#include "mem_ops_aligned.h" -#undef INCLUDED_BY_MEM_OPS_H - -#undef mem_get_be16 -#define mem_get_be16 mem_ops_wrap_symbol(mem_get_be16) -static unsigned MEM_VALUE_T mem_get_be16(const void *vmem) -{ - unsigned MEM_VALUE_T val; - const MAU_T *mem = (const MAU_T *)vmem; - - val = mem[0] << 8; - val |= mem[1]; - return val; -} - -#undef mem_get_be24 -#define mem_get_be24 mem_ops_wrap_symbol(mem_get_be24) -static unsigned MEM_VALUE_T mem_get_be24(const void *vmem) -{ - unsigned MEM_VALUE_T val; - const MAU_T *mem = (const MAU_T *)vmem; - - val = mem[0] << 16; - val |= mem[1] << 8; - val |= mem[2]; - return val; -} - -#undef mem_get_be32 -#define mem_get_be32 mem_ops_wrap_symbol(mem_get_be32) -static unsigned MEM_VALUE_T mem_get_be32(const void *vmem) -{ - unsigned MEM_VALUE_T val; - const MAU_T *mem = (const MAU_T *)vmem; - - val = mem[0] << 24; - val |= mem[1] << 16; - val |= mem[2] << 8; - val |= mem[3]; - return val; -} - -#undef mem_get_le16 -#define mem_get_le16 mem_ops_wrap_symbol(mem_get_le16) -static unsigned MEM_VALUE_T mem_get_le16(const void *vmem) -{ - unsigned MEM_VALUE_T val; - const MAU_T *mem = (const MAU_T *)vmem; - - val = mem[1] << 8; - val |= mem[0]; - return val; -} - -#undef mem_get_le24 -#define mem_get_le24 mem_ops_wrap_symbol(mem_get_le24) -static unsigned MEM_VALUE_T mem_get_le24(const void *vmem) -{ - unsigned MEM_VALUE_T val; - const MAU_T *mem = (const MAU_T *)vmem; - - val = mem[2] << 16; - val |= mem[1] << 8; - val |= mem[0]; - return val; -} - -#undef mem_get_le32 -#define mem_get_le32 mem_ops_wrap_symbol(mem_get_le32) -static unsigned MEM_VALUE_T mem_get_le32(const void *vmem) -{ - unsigned MEM_VALUE_T val; - const MAU_T *mem = (const MAU_T *)vmem; - - val = mem[3] << 24; - val |= mem[2] << 16; - val |= mem[1] << 8; - val |= mem[0]; - return val; -} - -#define mem_get_s_generic(end,sz) \ - static signed MEM_VALUE_T mem_get_s##end##sz(const void *vmem) {\ - const MAU_T *mem = (const MAU_T*)vmem;\ - signed MEM_VALUE_T val = mem_get_##end##sz(mem);\ - return (val << (MEM_VALUE_T_SZ_BITS - sz)) >> (MEM_VALUE_T_SZ_BITS - sz);\ - } - -#undef mem_get_sbe16 -#define mem_get_sbe16 mem_ops_wrap_symbol(mem_get_sbe16) -mem_get_s_generic(be, 16); - -#undef mem_get_sbe24 -#define mem_get_sbe24 mem_ops_wrap_symbol(mem_get_sbe24) -mem_get_s_generic(be, 24); - -#undef mem_get_sbe32 -#define mem_get_sbe32 mem_ops_wrap_symbol(mem_get_sbe32) -mem_get_s_generic(be, 32); - -#undef mem_get_sle16 -#define mem_get_sle16 mem_ops_wrap_symbol(mem_get_sle16) -mem_get_s_generic(le, 16); - -#undef mem_get_sle24 -#define mem_get_sle24 mem_ops_wrap_symbol(mem_get_sle24) -mem_get_s_generic(le, 24); - -#undef mem_get_sle32 -#define mem_get_sle32 mem_ops_wrap_symbol(mem_get_sle32) -mem_get_s_generic(le, 32); - -#undef mem_put_be16 -#define mem_put_be16 mem_ops_wrap_symbol(mem_put_be16) -static void mem_put_be16(void *vmem, MEM_VALUE_T val) -{ - MAU_T *mem = (MAU_T *)vmem; - - mem[0] = (val >> 8) & 0xff; - mem[1] = (val >> 0) & 0xff; -} - -#undef mem_put_be24 -#define mem_put_be24 mem_ops_wrap_symbol(mem_put_be24) -static void mem_put_be24(void *vmem, MEM_VALUE_T val) -{ - MAU_T *mem = (MAU_T *)vmem; - - mem[0] = (val >> 16) & 0xff; - mem[1] = (val >> 8) & 0xff; - mem[2] = (val >> 0) & 0xff; -} - -#undef mem_put_be32 -#define mem_put_be32 mem_ops_wrap_symbol(mem_put_be32) -static void mem_put_be32(void *vmem, MEM_VALUE_T val) -{ - MAU_T *mem = (MAU_T *)vmem; - - mem[0] = (val >> 24) & 0xff; - mem[1] = (val >> 16) & 0xff; - mem[2] = (val >> 8) & 0xff; - mem[3] = (val >> 0) & 0xff; -} - -#undef mem_put_le16 -#define mem_put_le16 mem_ops_wrap_symbol(mem_put_le16) -static void mem_put_le16(void *vmem, MEM_VALUE_T val) -{ - MAU_T *mem = (MAU_T *)vmem; - - mem[0] = (val >> 0) & 0xff; - mem[1] = (val >> 8) & 0xff; -} - -#undef mem_put_le24 -#define mem_put_le24 mem_ops_wrap_symbol(mem_put_le24) -static void mem_put_le24(void *vmem, MEM_VALUE_T val) -{ - MAU_T *mem = (MAU_T *)vmem; - - mem[0] = (val >> 0) & 0xff; - mem[1] = (val >> 8) & 0xff; - mem[2] = (val >> 16) & 0xff; -} - -#undef mem_put_le32 -#define mem_put_le32 mem_ops_wrap_symbol(mem_put_le32) -static void mem_put_le32(void *vmem, MEM_VALUE_T val) -{ - MAU_T *mem = (MAU_T *)vmem; - - mem[0] = (val >> 0) & 0xff; - mem[1] = (val >> 8) & 0xff; - mem[2] = (val >> 16) & 0xff; - mem[3] = (val >> 24) & 0xff; -} diff --git a/wcap/mem_ops_aligned.h b/wcap/mem_ops_aligned.h deleted file mode 100644 index 0fbba65..0000000 --- a/wcap/mem_ops_aligned.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -/* \file - * \brief Provides portable memory access primitives for operating on aligned - * data - * - * This file is split from mem_ops.h for easier maintenance. See mem_ops.h - * for a more detailed description of these primitives. - */ -#ifndef INCLUDED_BY_MEM_OPS_H -#error Include mem_ops.h, not mem_ops_aligned.h directly. -#endif - -/* Architectures that provide instructions for doing this byte swapping - * could redefine these macros. - */ -#define swap_endian_16(val,raw) do {\ - val = ((raw>>8) & 0x00ff) \ - | ((raw<<8) & 0xff00);\ - } while(0) -#define swap_endian_32(val,raw) do {\ - val = ((raw>>24) & 0x000000ff) \ - | ((raw>>8) & 0x0000ff00) \ - | ((raw<<8) & 0x00ff0000) \ - | ((raw<<24) & 0xff000000); \ - } while(0) -#define swap_endian_16_se(val,raw) do {\ - swap_endian_16(val,raw);\ - val = ((val << 16) >> 16);\ - } while(0) -#define swap_endian_32_se(val,raw) swap_endian_32(val,raw) - -#define mem_get_ne_aligned_generic(end,sz) \ - static unsigned MEM_VALUE_T mem_get_##end##sz##_aligned(const void *vmem) {\ - const uint##sz##_t *mem = (const uint##sz##_t *)vmem;\ - return *mem;\ - } - -#define mem_get_sne_aligned_generic(end,sz) \ - static signed MEM_VALUE_T mem_get_s##end##sz##_aligned(const void *vmem) {\ - const int##sz##_t *mem = (const int##sz##_t *)vmem;\ - return *mem;\ - } - -#define mem_get_se_aligned_generic(end,sz) \ - static unsigned MEM_VALUE_T mem_get_##end##sz##_aligned(const void *vmem) {\ - const uint##sz##_t *mem = (const uint##sz##_t *)vmem;\ - unsigned MEM_VALUE_T val, raw = *mem;\ - swap_endian_##sz(val,raw);\ - return val;\ - } - -#define mem_get_sse_aligned_generic(end,sz) \ - static signed MEM_VALUE_T mem_get_s##end##sz##_aligned(const void *vmem) {\ - const int##sz##_t *mem = (const int##sz##_t *)vmem;\ - unsigned MEM_VALUE_T val, raw = *mem;\ - swap_endian_##sz##_se(val,raw);\ - return val;\ - } - -#define mem_put_ne_aligned_generic(end,sz) \ - static void mem_put_##end##sz##_aligned(void *vmem, MEM_VALUE_T val) {\ - uint##sz##_t *mem = (uint##sz##_t *)vmem;\ - *mem = (uint##sz##_t)val;\ - } - -#define mem_put_se_aligned_generic(end,sz) \ - static void mem_put_##end##sz##_aligned(void *vmem, MEM_VALUE_T val) {\ - uint##sz##_t *mem = (uint##sz##_t *)vmem, raw;\ - swap_endian_##sz(raw,val);\ - *mem = (uint##sz##_t)raw;\ - } - -#include "vpx_config.h" -#if CONFIG_BIG_ENDIAN -#define mem_get_be_aligned_generic(sz) mem_get_ne_aligned_generic(be,sz) -#define mem_get_sbe_aligned_generic(sz) mem_get_sne_aligned_generic(be,sz) -#define mem_get_le_aligned_generic(sz) mem_get_se_aligned_generic(le,sz) -#define mem_get_sle_aligned_generic(sz) mem_get_sse_aligned_generic(le,sz) -#define mem_put_be_aligned_generic(sz) mem_put_ne_aligned_generic(be,sz) -#define mem_put_le_aligned_generic(sz) mem_put_se_aligned_generic(le,sz) -#else -#define mem_get_be_aligned_generic(sz) mem_get_se_aligned_generic(be,sz) -#define mem_get_sbe_aligned_generic(sz) mem_get_sse_aligned_generic(be,sz) -#define mem_get_le_aligned_generic(sz) mem_get_ne_aligned_generic(le,sz) -#define mem_get_sle_aligned_generic(sz) mem_get_sne_aligned_generic(le,sz) -#define mem_put_be_aligned_generic(sz) mem_put_se_aligned_generic(be,sz) -#define mem_put_le_aligned_generic(sz) mem_put_ne_aligned_generic(le,sz) -#endif - -#undef mem_get_be16_aligned -#define mem_get_be16_aligned mem_ops_wrap_symbol(mem_get_be16_aligned) -mem_get_be_aligned_generic(16); - -#undef mem_get_be32_aligned -#define mem_get_be32_aligned mem_ops_wrap_symbol(mem_get_be32_aligned) -mem_get_be_aligned_generic(32); - -#undef mem_get_le16_aligned -#define mem_get_le16_aligned mem_ops_wrap_symbol(mem_get_le16_aligned) -mem_get_le_aligned_generic(16); - -#undef mem_get_le32_aligned -#define mem_get_le32_aligned mem_ops_wrap_symbol(mem_get_le32_aligned) -mem_get_le_aligned_generic(32); - -#undef mem_get_sbe16_aligned -#define mem_get_sbe16_aligned mem_ops_wrap_symbol(mem_get_sbe16_aligned) -mem_get_sbe_aligned_generic(16); - -#undef mem_get_sbe32_aligned -#define mem_get_sbe32_aligned mem_ops_wrap_symbol(mem_get_sbe32_aligned) -mem_get_sbe_aligned_generic(32); - -#undef mem_get_sle16_aligned -#define mem_get_sle16_aligned mem_ops_wrap_symbol(mem_get_sle16_aligned) -mem_get_sle_aligned_generic(16); - -#undef mem_get_sle32_aligned -#define mem_get_sle32_aligned mem_ops_wrap_symbol(mem_get_sle32_aligned) -mem_get_sle_aligned_generic(32); - -#undef mem_put_be16_aligned -#define mem_put_be16_aligned mem_ops_wrap_symbol(mem_put_be16_aligned) -mem_put_be_aligned_generic(16); - -#undef mem_put_be32_aligned -#define mem_put_be32_aligned mem_ops_wrap_symbol(mem_put_be32_aligned) -mem_put_be_aligned_generic(32); - -#undef mem_put_le16_aligned -#define mem_put_le16_aligned mem_ops_wrap_symbol(mem_put_le16_aligned) -mem_put_le_aligned_generic(16); - -#undef mem_put_le32_aligned -#define mem_put_le32_aligned mem_ops_wrap_symbol(mem_put_le32_aligned) -mem_put_le_aligned_generic(32); - -#undef mem_get_ne_aligned_generic -#undef mem_get_se_aligned_generic -#undef mem_get_sne_aligned_generic -#undef mem_get_sse_aligned_generic -#undef mem_put_ne_aligned_generic -#undef mem_put_se_aligned_generic -#undef swap_endian_16 -#undef swap_endian_32 -#undef swap_endian_16_se -#undef swap_endian_32_se diff --git a/wcap/tools_common.c b/wcap/tools_common.c deleted file mode 100644 index 6f95028..0000000 --- a/wcap/tools_common.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#include -#include "tools_common.h" -#if defined(_WIN32) || defined(__OS2__) -#include -#include - -#ifdef __OS2__ -#define _setmode setmode -#define _fileno fileno -#define _O_BINARY O_BINARY -#endif -#endif - -FILE* set_binary_mode(FILE *stream) -{ - (void)stream; -#if defined(_WIN32) || defined(__OS2__) - _setmode(_fileno(stream), _O_BINARY); -#endif - return stream; -} diff --git a/wcap/tools_common.h b/wcap/tools_common.h deleted file mode 100644 index 80c9747..0000000 --- a/wcap/tools_common.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#ifndef TOOLS_COMMON_H -#define TOOLS_COMMON_H - -/* Sets a stdio stream into binary mode */ -FILE* set_binary_mode(FILE *stream); - -#endif diff --git a/wcap/vpx_config.h b/wcap/vpx_config.h deleted file mode 100644 index b4e8c30..0000000 --- a/wcap/vpx_config.h +++ /dev/null @@ -1,2 +0,0 @@ - -#define CONFIG_LITTLE_ENDIAN 1 diff --git a/wcap/vpx_timer.h b/wcap/vpx_timer.h deleted file mode 100644 index d07e086..0000000 --- a/wcap/vpx_timer.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -#ifndef VPX_TIMER_H -#define VPX_TIMER_H -#include "vpx/vpx_integer.h" - -#if CONFIG_OS_SUPPORT - -#if defined(_WIN32) -/* - * Win32 specific includes - */ -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#else -/* - * POSIX specific includes - */ -#include - -/* timersub is not provided by msys at this time. */ -#ifndef timersub -#define timersub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ - } while (0) -#endif -#endif - - -struct vpx_usec_timer -{ -#if defined(_WIN32) - LARGE_INTEGER begin, end; -#else - struct timeval begin, end; -#endif -}; - - -static void -vpx_usec_timer_start(struct vpx_usec_timer *t) -{ -#if defined(_WIN32) - QueryPerformanceCounter(&t->begin); -#else - gettimeofday(&t->begin, NULL); -#endif -} - - -static void -vpx_usec_timer_mark(struct vpx_usec_timer *t) -{ -#if defined(_WIN32) - QueryPerformanceCounter(&t->end); -#else - gettimeofday(&t->end, NULL); -#endif -} - - -static int64_t -vpx_usec_timer_elapsed(struct vpx_usec_timer *t) -{ -#if defined(_WIN32) - LARGE_INTEGER freq, diff; - - diff.QuadPart = t->end.QuadPart - t->begin.QuadPart; - - QueryPerformanceFrequency(&freq); - return diff.QuadPart * 1000000 / freq.QuadPart; -#else - struct timeval diff; - - timersub(&t->end, &t->begin, &diff); - return diff.tv_sec * 1000000 + diff.tv_usec; -#endif -} - -#else /* CONFIG_OS_SUPPORT = 0*/ - -/* Empty timer functions if CONFIG_OS_SUPPORT = 0 */ -#ifndef timersub -#define timersub(a, b, result) -#endif - -struct vpx_usec_timer -{ - void *dummy; -}; - -static void -vpx_usec_timer_start(struct vpx_usec_timer *t) { } - -static void -vpx_usec_timer_mark(struct vpx_usec_timer *t) { } - -static long -vpx_usec_timer_elapsed(struct vpx_usec_timer *t) { return 0; } - -#endif /* CONFIG_OS_SUPPORT */ - -#endif diff --git a/wcap/vpxenc.c b/wcap/vpxenc.c deleted file mode 100644 index 5e9e34d..0000000 --- a/wcap/vpxenc.c +++ /dev/null @@ -1,2664 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -/* This is a simple program that encodes YV12 files and generates ivf - * files using the new interface. - */ -#if defined(_WIN32) || !CONFIG_OS_SUPPORT -#define USE_POSIX_MMAP 0 -#else -#define USE_POSIX_MMAP 1 -#endif - -#include -#include -#include -#include -#include -#include -#include "vpx/vpx_encoder.h" -#if USE_POSIX_MMAP -#include -#include -#include -#include -#include -#endif -#include "vpx/vp8cx.h" -#include "mem_ops.h" -#include "vpx_timer.h" -#include "tools_common.h" -#include "y4minput.h" -#include "EbmlWriter.h" -#include "EbmlIDs.h" - -#include "wcap-decode.h" - -/* Need special handling of these functions on Windows */ -#if defined(_MSC_VER) -/* MSVS doesn't define off_t, and uses _f{seek,tell}i64 */ -typedef __int64 off_t; -#define fseeko _fseeki64 -#define ftello _ftelli64 -#elif defined(_WIN32) -/* MinGW defines off_t as long - and uses f{seek,tell}o64/off64_t for large files */ -#define fseeko fseeko64 -#define ftello ftello64 -#define off_t off64_t -#endif - -#if defined(_MSC_VER) -#define LITERALU64(n) n -#else -#define LITERALU64(n) n##LLU -#endif - -/* We should use 32-bit file operations in WebM file format - * when building ARM executable file (.axf) with RVCT */ -#if !CONFIG_OS_SUPPORT -typedef long off_t; -#define fseeko fseek -#define ftello ftell -#endif - -static const char *exec_name; - -static const struct codec_item -{ - char const *name; - const vpx_codec_iface_t *iface; - unsigned int fourcc; -} codecs[] = -{ -#if CONFIG_VP8_ENCODER - {"vp8", &vpx_codec_vp8_cx_algo, 0x30385056}, -#endif -}; - -static void usage_exit(); - -#define LOG_ERROR(label) do \ -{\ - const char *l=label;\ - va_list ap;\ - va_start(ap, fmt);\ - if(l)\ - fprintf(stderr, "%s: ", l);\ - vfprintf(stderr, fmt, ap);\ - fprintf(stderr, "\n");\ - va_end(ap);\ -} while(0) - -void die(const char *fmt, ...) -{ - LOG_ERROR(NULL); - usage_exit(); -} - - -void fatal(const char *fmt, ...) -{ - LOG_ERROR("Fatal"); - exit(EXIT_FAILURE); -} - - -void warn(const char *fmt, ...) -{ - LOG_ERROR("Warning"); -} - - -static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) -{ - va_list ap; - - va_start(ap, s); - if (ctx->err) - { - const char *detail = vpx_codec_error_detail(ctx); - - vfprintf(stderr, s, ap); - fprintf(stderr, ": %s\n", vpx_codec_error(ctx)); - - if (detail) - fprintf(stderr, " %s\n", detail); - - exit(EXIT_FAILURE); - } -} - -/* This structure is used to abstract the different ways of handling - * first pass statistics. - */ -typedef struct -{ - vpx_fixed_buf_t buf; - int pass; - FILE *file; - char *buf_ptr; - size_t buf_alloc_sz; -} stats_io_t; - -int stats_open_file(stats_io_t *stats, const char *fpf, int pass) -{ - int res; - - stats->pass = pass; - - if (pass == 0) - { - stats->file = fopen(fpf, "wb"); - stats->buf.sz = 0; - stats->buf.buf = NULL, - res = (stats->file != NULL); - } - else - { -#if 0 -#elif USE_POSIX_MMAP - struct stat stat_buf; - int fd; - - fd = open(fpf, O_RDONLY); - stats->file = fdopen(fd, "rb"); - fstat(fd, &stat_buf); - stats->buf.sz = stat_buf.st_size; - stats->buf.buf = mmap(NULL, stats->buf.sz, PROT_READ, MAP_PRIVATE, - fd, 0); - res = (stats->buf.buf != NULL); -#else - size_t nbytes; - - stats->file = fopen(fpf, "rb"); - - if (fseek(stats->file, 0, SEEK_END)) - fatal("First-pass stats file must be seekable!"); - - stats->buf.sz = stats->buf_alloc_sz = ftell(stats->file); - rewind(stats->file); - - stats->buf.buf = malloc(stats->buf_alloc_sz); - - if (!stats->buf.buf) - fatal("Failed to allocate first-pass stats buffer (%lu bytes)", - (unsigned long)stats->buf_alloc_sz); - - nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file); - res = (nbytes == stats->buf.sz); -#endif - } - - return res; -} - -int stats_open_mem(stats_io_t *stats, int pass) -{ - int res; - stats->pass = pass; - - if (!pass) - { - stats->buf.sz = 0; - stats->buf_alloc_sz = 64 * 1024; - stats->buf.buf = malloc(stats->buf_alloc_sz); - } - - stats->buf_ptr = stats->buf.buf; - res = (stats->buf.buf != NULL); - return res; -} - - -void stats_close(stats_io_t *stats, int last_pass) -{ - if (stats->file) - { - if (stats->pass == last_pass) - { -#if 0 -#elif USE_POSIX_MMAP - munmap(stats->buf.buf, stats->buf.sz); -#else - free(stats->buf.buf); -#endif - } - - fclose(stats->file); - stats->file = NULL; - } - else - { - if (stats->pass == last_pass) - free(stats->buf.buf); - } -} - -void stats_write(stats_io_t *stats, const void *pkt, size_t len) -{ - if (stats->file) - { - if(fwrite(pkt, 1, len, stats->file)); - } - else - { - if (stats->buf.sz + len > stats->buf_alloc_sz) - { - size_t new_sz = stats->buf_alloc_sz + 64 * 1024; - char *new_ptr = realloc(stats->buf.buf, new_sz); - - if (new_ptr) - { - stats->buf_ptr = new_ptr + (stats->buf_ptr - (char *)stats->buf.buf); - stats->buf.buf = new_ptr; - stats->buf_alloc_sz = new_sz; - } - else - fatal("Failed to realloc firstpass stats buffer."); - } - - memcpy(stats->buf_ptr, pkt, len); - stats->buf.sz += len; - stats->buf_ptr += len; - } -} - -vpx_fixed_buf_t stats_get(stats_io_t *stats) -{ - return stats->buf; -} - -/* Stereo 3D packed frame format */ -typedef enum stereo_format -{ - STEREO_FORMAT_MONO = 0, - STEREO_FORMAT_LEFT_RIGHT = 1, - STEREO_FORMAT_BOTTOM_TOP = 2, - STEREO_FORMAT_TOP_BOTTOM = 3, - STEREO_FORMAT_RIGHT_LEFT = 11 -} stereo_format_t; - -enum video_file_type -{ - FILE_TYPE_RAW, - FILE_TYPE_IVF, - FILE_TYPE_Y4M, - FILE_TYPE_WCAP -}; - -struct detect_buffer { - char buf[4]; - size_t buf_read; - size_t position; -}; - - -struct input_state -{ - char *fn; - FILE *file; - y4m_input y4m; - struct detect_buffer detect; - enum video_file_type file_type; - unsigned int w; - unsigned int h; - struct vpx_rational framerate; - int use_i420; - struct wcap_decoder *wcap; - uint32_t output_msecs; - struct vpx_rational output_framerate; -}; - -static inline int rgb_to_yuv(uint32_t format, uint32_t p, int *u, int *v) -{ - int r, g, b, y; - - switch (format) { - case WCAP_FORMAT_XRGB8888: - r = (p >> 16) & 0xff; - g = (p >> 8) & 0xff; - b = (p >> 0) & 0xff; - break; - case WCAP_FORMAT_XBGR8888: - r = (p >> 0) & 0xff; - g = (p >> 8) & 0xff; - b = (p >> 16) & 0xff; - break; - } - - y = (19595 * r + 38469 * g + 7472 * b) >> 16; - if (y > 255) - y = 255; - - *u += 46727 * (r - y); - *v += 36962 * (b - y); - - return y; -} - -static inline int clamp_uv(int u) -{ - int clamp = (u >> 18) + 128; - - if (clamp < 0) - return 0; - else if (clamp > 255) - return 255; - else - return clamp; -} - -void convert_to_yv12(struct wcap_decoder *wcap, vpx_image_t *img) -{ - unsigned char *y1, *y2, *u, *v; - uint32_t *p1, *p2, *end; - int i, u_accum, v_accum; - uint32_t format = wcap->format; - - for (i = 0; i < wcap->height; i += 2) { - y1 = img->planes[0] + img->stride[0] * i; - y2 = img->planes[0] + img->stride[0] * i + img->stride[0]; - u = img->planes[2] + img->stride[2] * i / 2; - v = img->planes[1] + img->stride[1] * i / 2; - p1 = wcap->frame + wcap->width * i; - p2 = wcap->frame + wcap->width * i + wcap->width; - end = p1 + wcap->width; - - while (p1 < end) { - u_accum = 0; - v_accum = 0; - y1[0] = rgb_to_yuv(format, p1[0], &u_accum, &v_accum); - y1[1] = rgb_to_yuv(format, p1[1], &u_accum, &v_accum); - y2[0] = rgb_to_yuv(format, p2[0], &u_accum, &v_accum); - y2[1] = rgb_to_yuv(format, p2[1], &u_accum, &v_accum); - u[0] = clamp_uv(u_accum); - v[0] = clamp_uv(v_accum); - - y1 += 2; - p1 += 2; - y2 += 2; - p2 += 2; - u++; - v++; - } - } -} - -#define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */ -static int read_frame(struct input_state *input, vpx_image_t *img) -{ - FILE *f = input->file; - enum video_file_type file_type = input->file_type; - y4m_input *y4m = &input->y4m; - struct detect_buffer *detect = &input->detect; - int plane = 0; - int shortread = 0; - - if (file_type == FILE_TYPE_Y4M) - { - if (y4m_input_fetch_frame(y4m, f, img) < 1) - return 0; - } - else if (file_type == FILE_TYPE_WCAP) - { - if (input->wcap->count == 0) { - wcap_decoder_get_frame(input->wcap); - input->output_msecs = input->wcap->msecs; - } - - while (input->output_msecs - input->wcap->msecs < INT32_MAX) - if (!wcap_decoder_get_frame(input->wcap)) - return 0; - - convert_to_yv12(input->wcap, img); - input->output_msecs += - input->framerate.den * 1000 / input->framerate.num; - } - else - { - if (file_type == FILE_TYPE_IVF) - { - char junk[IVF_FRAME_HDR_SZ]; - - /* Skip the frame header. We know how big the frame should be. See - * write_ivf_frame_header() for documentation on the frame header - * layout. - */ - if(fread(junk, 1, IVF_FRAME_HDR_SZ, f)); - } - - for (plane = 0; plane < 3; plane++) - { - unsigned char *ptr; - int w = (plane ? (1 + img->d_w) / 2 : img->d_w); - int h = (plane ? (1 + img->d_h) / 2 : img->d_h); - int r; - - /* Determine the correct plane based on the image format. The for-loop - * always counts in Y,U,V order, but this may not match the order of - * the data on disk. - */ - switch (plane) - { - case 1: - ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U]; - break; - case 2: - ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V]; - break; - default: - ptr = img->planes[plane]; - } - - for (r = 0; r < h; r++) - { - size_t needed = w; - size_t buf_position = 0; - const size_t left = detect->buf_read - detect->position; - if (left > 0) - { - const size_t more = (left < needed) ? left : needed; - memcpy(ptr, detect->buf + detect->position, more); - buf_position = more; - needed -= more; - detect->position += more; - } - if (needed > 0) - { - shortread |= (fread(ptr + buf_position, 1, needed, f) < needed); - } - - ptr += img->stride[plane]; - } - } - } - - return !shortread; -} - - -unsigned int file_is_y4m(FILE *infile, - y4m_input *y4m, - char detect[4]) -{ - if(memcmp(detect, "YUV4", 4) == 0) - { - return 1; - } - return 0; -} - -#define IVF_FILE_HDR_SZ (32) -unsigned int file_is_ivf(struct input_state *input, - unsigned int *fourcc) -{ - char raw_hdr[IVF_FILE_HDR_SZ]; - int is_ivf = 0; - FILE *infile = input->file; - unsigned int *width = &input->w; - unsigned int *height = &input->h; - struct detect_buffer *detect = &input->detect; - - if(memcmp(detect->buf, "DKIF", 4) != 0) - return 0; - - /* See write_ivf_file_header() for more documentation on the file header - * layout. - */ - if (fread(raw_hdr + 4, 1, IVF_FILE_HDR_SZ - 4, infile) - == IVF_FILE_HDR_SZ - 4) - { - { - is_ivf = 1; - - if (mem_get_le16(raw_hdr + 4) != 0) - warn("Unrecognized IVF version! This file may not decode " - "properly."); - - *fourcc = mem_get_le32(raw_hdr + 8); - } - } - - if (is_ivf) - { - *width = mem_get_le16(raw_hdr + 12); - *height = mem_get_le16(raw_hdr + 14); - detect->position = 4; - } - - return is_ivf; -} - -unsigned int file_is_wcap(struct input_state *input) -{ - if(mem_get_le32(input->detect.buf) == WCAP_HEADER_MAGIC) - return 1; - - return 0; -} - -static void write_ivf_file_header(FILE *outfile, - const vpx_codec_enc_cfg_t *cfg, - unsigned int fourcc, - int frame_cnt) -{ - char header[32]; - - if (cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) - return; - - header[0] = 'D'; - header[1] = 'K'; - header[2] = 'I'; - header[3] = 'F'; - mem_put_le16(header + 4, 0); /* version */ - mem_put_le16(header + 6, 32); /* headersize */ - mem_put_le32(header + 8, fourcc); /* headersize */ - mem_put_le16(header + 12, cfg->g_w); /* width */ - mem_put_le16(header + 14, cfg->g_h); /* height */ - mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */ - mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */ - mem_put_le32(header + 24, frame_cnt); /* length */ - mem_put_le32(header + 28, 0); /* unused */ - - if(fwrite(header, 1, 32, outfile)); -} - - -static void write_ivf_frame_header(FILE *outfile, - const vpx_codec_cx_pkt_t *pkt) -{ - char header[12]; - vpx_codec_pts_t pts; - - if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) - return; - - pts = pkt->data.frame.pts; - mem_put_le32(header, pkt->data.frame.sz); - mem_put_le32(header + 4, pts & 0xFFFFFFFF); - mem_put_le32(header + 8, pts >> 32); - - if(fwrite(header, 1, 12, outfile)); -} - -static void write_ivf_frame_size(FILE *outfile, size_t size) -{ - char header[4]; - mem_put_le32(header, size); - fwrite(header, 1, 4, outfile); -} - - -typedef off_t EbmlLoc; - - -struct cue_entry -{ - unsigned int time; - uint64_t loc; -}; - - -struct EbmlGlobal -{ - int debug; - - FILE *stream; - int64_t last_pts_ms; - vpx_rational_t framerate; - - /* These pointers are to the start of an element */ - off_t position_reference; - off_t seek_info_pos; - off_t segment_info_pos; - off_t track_pos; - off_t cue_pos; - off_t cluster_pos; - - /* This pointer is to a specific element to be serialized */ - off_t track_id_pos; - - /* These pointers are to the size field of the element */ - EbmlLoc startSegment; - EbmlLoc startCluster; - - uint32_t cluster_timecode; - int cluster_open; - - struct cue_entry *cue_list; - unsigned int cues; - -}; - - -void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) -{ - if(fwrite(buffer_in, 1, len, glob->stream)); -} - -#define WRITE_BUFFER(s) \ -for(i = len-1; i>=0; i--)\ -{ \ - x = *(const s *)buffer_in >> (i * CHAR_BIT); \ - Ebml_Write(glob, &x, 1); \ -} -void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigned long len) -{ - char x; - int i; - - /* buffer_size: - * 1 - int8_t; - * 2 - int16_t; - * 3 - int32_t; - * 4 - int64_t; - */ - switch (buffer_size) - { - case 1: - WRITE_BUFFER(int8_t) - break; - case 2: - WRITE_BUFFER(int16_t) - break; - case 4: - WRITE_BUFFER(int32_t) - break; - case 8: - WRITE_BUFFER(int64_t) - break; - default: - break; - } -} -#undef WRITE_BUFFER - -/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit - * one, but not a 32 bit one. - */ -static void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) -{ - unsigned char sizeSerialized = 4 | 0x80; - Ebml_WriteID(glob, class_id); - Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); - Ebml_Serialize(glob, &ui, sizeof(ui), 4); -} - - -static void -Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, - unsigned long class_id) -{ - //todo this is always taking 8 bytes, this may need later optimization - //this is a key that says length unknown - uint64_t unknownLen = LITERALU64(0x01FFFFFFFFFFFFFF); - - Ebml_WriteID(glob, class_id); - *ebmlLoc = ftello(glob->stream); - Ebml_Serialize(glob, &unknownLen, sizeof(unknownLen), 8); -} - -static void -Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) -{ - off_t pos; - uint64_t size; - - /* Save the current stream pointer */ - pos = ftello(glob->stream); - - /* Calculate the size of this element */ - size = pos - *ebmlLoc - 8; - size |= LITERALU64(0x0100000000000000); - - /* Seek back to the beginning of the element and write the new size */ - fseeko(glob->stream, *ebmlLoc, SEEK_SET); - Ebml_Serialize(glob, &size, sizeof(size), 8); - - /* Reset the stream pointer */ - fseeko(glob->stream, pos, SEEK_SET); -} - - -static void -write_webm_seek_element(EbmlGlobal *ebml, unsigned long id, off_t pos) -{ - uint64_t offset = pos - ebml->position_reference; - EbmlLoc start; - Ebml_StartSubElement(ebml, &start, Seek); - Ebml_SerializeBinary(ebml, SeekID, id); - Ebml_SerializeUnsigned64(ebml, SeekPosition, offset); - Ebml_EndSubElement(ebml, &start); -} - - -static void -write_webm_seek_info(EbmlGlobal *ebml) -{ - - off_t pos; - - /* Save the current stream pointer */ - pos = ftello(ebml->stream); - - if(ebml->seek_info_pos) - fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET); - else - ebml->seek_info_pos = pos; - - { - EbmlLoc start; - - Ebml_StartSubElement(ebml, &start, SeekHead); - write_webm_seek_element(ebml, Tracks, ebml->track_pos); - write_webm_seek_element(ebml, Cues, ebml->cue_pos); - write_webm_seek_element(ebml, Info, ebml->segment_info_pos); - Ebml_EndSubElement(ebml, &start); - } - { - //segment info - EbmlLoc startInfo; - uint64_t frame_time; - char version_string[64]; - - /* Assemble version string */ - if(ebml->debug) - strcpy(version_string, "vpxenc"); - else - { - strcpy(version_string, "vpxenc "); - strncat(version_string, - vpx_codec_version_str(), - sizeof(version_string) - 1 - strlen(version_string)); - } - - frame_time = (uint64_t)1000 * ebml->framerate.den - / ebml->framerate.num; - ebml->segment_info_pos = ftello(ebml->stream); - Ebml_StartSubElement(ebml, &startInfo, Info); - Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); - Ebml_SerializeFloat(ebml, Segment_Duration, - ebml->last_pts_ms + frame_time); - Ebml_SerializeString(ebml, 0x4D80, version_string); - Ebml_SerializeString(ebml, 0x5741, version_string); - Ebml_EndSubElement(ebml, &startInfo); - } -} - - -static void -write_webm_file_header(EbmlGlobal *glob, - const vpx_codec_enc_cfg_t *cfg, - const struct vpx_rational *fps, - stereo_format_t stereo_fmt) -{ - { - EbmlLoc start; - Ebml_StartSubElement(glob, &start, EBML); - Ebml_SerializeUnsigned(glob, EBMLVersion, 1); - Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); //EBML Read Version - Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); //EBML Max ID Length - Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); //EBML Max Size Length - Ebml_SerializeString(glob, DocType, "webm"); //Doc Type - Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); //Doc Type Version - Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); //Doc Type Read Version - Ebml_EndSubElement(glob, &start); - } - { - Ebml_StartSubElement(glob, &glob->startSegment, Segment); //segment - glob->position_reference = ftello(glob->stream); - glob->framerate = *fps; - write_webm_seek_info(glob); - - { - EbmlLoc trackStart; - glob->track_pos = ftello(glob->stream); - Ebml_StartSubElement(glob, &trackStart, Tracks); - { - unsigned int trackNumber = 1; - uint64_t trackID = 0; - - EbmlLoc start; - Ebml_StartSubElement(glob, &start, TrackEntry); - Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); - glob->track_id_pos = ftello(glob->stream); - Ebml_SerializeUnsigned32(glob, TrackUID, trackID); - Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1 - Ebml_SerializeString(glob, CodecID, "V_VP8"); - { - unsigned int pixelWidth = cfg->g_w; - unsigned int pixelHeight = cfg->g_h; - float frameRate = (float)fps->num/(float)fps->den; - - EbmlLoc videoStart; - Ebml_StartSubElement(glob, &videoStart, Video); - Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); - Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); - Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt); - Ebml_SerializeFloat(glob, FrameRate, frameRate); - Ebml_EndSubElement(glob, &videoStart); //Video - } - Ebml_EndSubElement(glob, &start); //Track Entry - } - Ebml_EndSubElement(glob, &trackStart); - } - // segment element is open - } -} - - -static void -write_webm_block(EbmlGlobal *glob, - const vpx_codec_enc_cfg_t *cfg, - const vpx_codec_cx_pkt_t *pkt) -{ - unsigned long block_length; - unsigned char track_number; - unsigned short block_timecode = 0; - unsigned char flags; - int64_t pts_ms; - int start_cluster = 0, is_keyframe; - - /* Calculate the PTS of this frame in milliseconds */ - pts_ms = pkt->data.frame.pts * 1000 - * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; - if(pts_ms <= glob->last_pts_ms) - pts_ms = glob->last_pts_ms + 1; - glob->last_pts_ms = pts_ms; - - /* Calculate the relative time of this block */ - if(pts_ms - glob->cluster_timecode > SHRT_MAX) - start_cluster = 1; - else - block_timecode = pts_ms - glob->cluster_timecode; - - is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY); - if(start_cluster || is_keyframe) - { - if(glob->cluster_open) - Ebml_EndSubElement(glob, &glob->startCluster); - - /* Open the new cluster */ - block_timecode = 0; - glob->cluster_open = 1; - glob->cluster_timecode = pts_ms; - glob->cluster_pos = ftello(glob->stream); - Ebml_StartSubElement(glob, &glob->startCluster, Cluster); //cluster - Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode); - - /* Save a cue point if this is a keyframe. */ - if(is_keyframe) - { - struct cue_entry *cue, *new_cue_list; - - new_cue_list = realloc(glob->cue_list, - (glob->cues+1) * sizeof(struct cue_entry)); - if(new_cue_list) - glob->cue_list = new_cue_list; - else - fatal("Failed to realloc cue list."); - - cue = &glob->cue_list[glob->cues]; - cue->time = glob->cluster_timecode; - cue->loc = glob->cluster_pos; - glob->cues++; - } - } - - /* Write the Simple Block */ - Ebml_WriteID(glob, SimpleBlock); - - block_length = pkt->data.frame.sz + 4; - block_length |= 0x10000000; - Ebml_Serialize(glob, &block_length, sizeof(block_length), 4); - - track_number = 1; - track_number |= 0x80; - Ebml_Write(glob, &track_number, 1); - - Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2); - - flags = 0; - if(is_keyframe) - flags |= 0x80; - if(pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) - flags |= 0x08; - Ebml_Write(glob, &flags, 1); - - Ebml_Write(glob, pkt->data.frame.buf, pkt->data.frame.sz); -} - - -static void -write_webm_file_footer(EbmlGlobal *glob, long hash) -{ - - if(glob->cluster_open) - Ebml_EndSubElement(glob, &glob->startCluster); - - { - EbmlLoc start; - unsigned int i; - - glob->cue_pos = ftello(glob->stream); - Ebml_StartSubElement(glob, &start, Cues); - for(i=0; icues; i++) - { - struct cue_entry *cue = &glob->cue_list[i]; - EbmlLoc start; - - Ebml_StartSubElement(glob, &start, CuePoint); - { - EbmlLoc start; - - Ebml_SerializeUnsigned(glob, CueTime, cue->time); - - Ebml_StartSubElement(glob, &start, CueTrackPositions); - Ebml_SerializeUnsigned(glob, CueTrack, 1); - Ebml_SerializeUnsigned64(glob, CueClusterPosition, - cue->loc - glob->position_reference); - //Ebml_SerializeUnsigned(glob, CueBlockNumber, cue->blockNumber); - Ebml_EndSubElement(glob, &start); - } - Ebml_EndSubElement(glob, &start); - } - Ebml_EndSubElement(glob, &start); - } - - Ebml_EndSubElement(glob, &glob->startSegment); - - /* Patch up the seek info block */ - write_webm_seek_info(glob); - - /* Patch up the track id */ - fseeko(glob->stream, glob->track_id_pos, SEEK_SET); - Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash); - - fseeko(glob->stream, 0, SEEK_END); -} - - -/* Murmur hash derived from public domain reference implementation at - * http://sites.google.com/site/murmurhash/ - */ -static unsigned int murmur ( const void * key, int len, unsigned int seed ) -{ - const unsigned int m = 0x5bd1e995; - const int r = 24; - - unsigned int h = seed ^ len; - - const unsigned char * data = (const unsigned char *)key; - - while(len >= 4) - { - unsigned int k; - - k = data[0]; - k |= data[1] << 8; - k |= data[2] << 16; - k |= data[3] << 24; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - data += 4; - len -= 4; - } - - switch(len) - { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; - h *= m; - }; - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - -#include "math.h" - -static double vp8_mse2psnr(double Samples, double Peak, double Mse) -{ - double psnr; - - if ((double)Mse > 0.0) - psnr = 10.0 * log10(Peak * Peak * Samples / Mse); - else - psnr = 60; // Limit to prevent / 0 - - if (psnr > 60) - psnr = 60; - - return psnr; -} - - -#include "args.h" -static const arg_def_t debugmode = ARG_DEF("D", "debug", 0, - "Debug mode (makes output deterministic)"); -static const arg_def_t outputfile = ARG_DEF("o", "output", 1, - "Output filename"); -static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, - "Input file is YV12 "); -static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, - "Input file is I420 (default)"); -static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, - "Codec to use"); -static const arg_def_t passes = ARG_DEF("p", "passes", 1, - "Number of passes (1/2)"); -static const arg_def_t pass_arg = ARG_DEF(NULL, "pass", 1, - "Pass to execute (1/2)"); -static const arg_def_t fpf_name = ARG_DEF(NULL, "fpf", 1, - "First pass statistics file name"); -static const arg_def_t limit = ARG_DEF(NULL, "limit", 1, - "Stop encoding after n input frames"); -static const arg_def_t deadline = ARG_DEF("d", "deadline", 1, - "Deadline per frame (usec)"); -static const arg_def_t best_dl = ARG_DEF(NULL, "best", 0, - "Use Best Quality Deadline"); -static const arg_def_t good_dl = ARG_DEF(NULL, "good", 0, - "Use Good Quality Deadline"); -static const arg_def_t rt_dl = ARG_DEF(NULL, "rt", 0, - "Use Realtime Quality Deadline"); -static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, - "Show encoder parameters"); -static const arg_def_t psnrarg = ARG_DEF(NULL, "psnr", 0, - "Show PSNR in status line"); -static const arg_def_t framerate = ARG_DEF(NULL, "fps", 1, - "Stream frame rate (rate/scale)"); -static const arg_def_t use_ivf = ARG_DEF(NULL, "ivf", 0, - "Output IVF (default is WebM)"); -static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0, - "Makes encoder output partitions. Requires IVF output!"); -static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1, - "Show quantizer histogram (n-buckets)"); -static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1, - "Show rate histogram (n-buckets)"); -static const arg_def_t *main_args[] = -{ - &debugmode, - &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &deadline, - &best_dl, &good_dl, &rt_dl, - &verbosearg, &psnrarg, &use_ivf, &out_part, &q_hist_n, &rate_hist_n, - NULL -}; - -static const arg_def_t usage = ARG_DEF("u", "usage", 1, - "Usage profile number to use"); -static const arg_def_t threads = ARG_DEF("t", "threads", 1, - "Max number of threads to use"); -static const arg_def_t profile = ARG_DEF(NULL, "profile", 1, - "Bitstream profile number to use"); -static const arg_def_t width = ARG_DEF("w", "width", 1, - "Frame width"); -static const arg_def_t height = ARG_DEF("h", "height", 1, - "Frame height"); -static const struct arg_enum_list stereo_mode_enum[] = { - {"mono" , STEREO_FORMAT_MONO}, - {"left-right", STEREO_FORMAT_LEFT_RIGHT}, - {"bottom-top", STEREO_FORMAT_BOTTOM_TOP}, - {"top-bottom", STEREO_FORMAT_TOP_BOTTOM}, - {"right-left", STEREO_FORMAT_RIGHT_LEFT}, - {NULL, 0} -}; -static const arg_def_t stereo_mode = ARG_DEF_ENUM(NULL, "stereo-mode", 1, - "Stereo 3D video format", stereo_mode_enum); -static const arg_def_t timebase = ARG_DEF(NULL, "timebase", 1, - "Output timestamp precision (fractional seconds)"); -static const arg_def_t error_resilient = ARG_DEF(NULL, "error-resilient", 1, - "Enable error resiliency features"); -static const arg_def_t lag_in_frames = ARG_DEF(NULL, "lag-in-frames", 1, - "Max number of frames to lag"); - -static const arg_def_t *global_args[] = -{ - &use_yv12, &use_i420, &usage, &threads, &profile, - &width, &height, &stereo_mode, &timebase, &framerate, &error_resilient, - &lag_in_frames, NULL -}; - -static const arg_def_t dropframe_thresh = ARG_DEF(NULL, "drop-frame", 1, - "Temporal resampling threshold (buf %)"); -static const arg_def_t resize_allowed = ARG_DEF(NULL, "resize-allowed", 1, - "Spatial resampling enabled (bool)"); -static const arg_def_t resize_up_thresh = ARG_DEF(NULL, "resize-up", 1, - "Upscale threshold (buf %)"); -static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1, - "Downscale threshold (buf %)"); -static const struct arg_enum_list end_usage_enum[] = { - {"vbr", VPX_VBR}, - {"cbr", VPX_CBR}, - {"cq", VPX_CQ}, - {NULL, 0} -}; -static const arg_def_t end_usage = ARG_DEF_ENUM(NULL, "end-usage", 1, - "Rate control mode", end_usage_enum); -static const arg_def_t target_bitrate = ARG_DEF(NULL, "target-bitrate", 1, - "Bitrate (kbps)"); -static const arg_def_t min_quantizer = ARG_DEF(NULL, "min-q", 1, - "Minimum (best) quantizer"); -static const arg_def_t max_quantizer = ARG_DEF(NULL, "max-q", 1, - "Maximum (worst) quantizer"); -static const arg_def_t undershoot_pct = ARG_DEF(NULL, "undershoot-pct", 1, - "Datarate undershoot (min) target (%)"); -static const arg_def_t overshoot_pct = ARG_DEF(NULL, "overshoot-pct", 1, - "Datarate overshoot (max) target (%)"); -static const arg_def_t buf_sz = ARG_DEF(NULL, "buf-sz", 1, - "Client buffer size (ms)"); -static const arg_def_t buf_initial_sz = ARG_DEF(NULL, "buf-initial-sz", 1, - "Client initial buffer size (ms)"); -static const arg_def_t buf_optimal_sz = ARG_DEF(NULL, "buf-optimal-sz", 1, - "Client optimal buffer size (ms)"); -static const arg_def_t *rc_args[] = -{ - &dropframe_thresh, &resize_allowed, &resize_up_thresh, &resize_down_thresh, - &end_usage, &target_bitrate, &min_quantizer, &max_quantizer, - &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz, - NULL -}; - - -static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1, - "CBR/VBR bias (0=CBR, 100=VBR)"); -static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1, - "GOP min bitrate (% of target)"); -static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1, - "GOP max bitrate (% of target)"); -static const arg_def_t *rc_twopass_args[] = -{ - &bias_pct, &minsection_pct, &maxsection_pct, NULL -}; - - -static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1, - "Minimum keyframe interval (frames)"); -static const arg_def_t kf_max_dist = ARG_DEF(NULL, "kf-max-dist", 1, - "Maximum keyframe interval (frames)"); -static const arg_def_t kf_disabled = ARG_DEF(NULL, "disable-kf", 0, - "Disable keyframe placement"); -static const arg_def_t *kf_args[] = -{ - &kf_min_dist, &kf_max_dist, &kf_disabled, NULL -}; - - -#if CONFIG_VP8_ENCODER -static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1, - "Noise sensitivity (frames to blur)"); -static const arg_def_t sharpness = ARG_DEF(NULL, "sharpness", 1, - "Filter sharpness (0-7)"); -static const arg_def_t static_thresh = ARG_DEF(NULL, "static-thresh", 1, - "Motion detection threshold"); -#endif - -#if CONFIG_VP8_ENCODER -static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1, - "CPU Used (-16..16)"); -#endif - - -#if CONFIG_VP8_ENCODER -static const arg_def_t token_parts = ARG_DEF(NULL, "token-parts", 1, - "Number of token partitions to use, log2"); -static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1, - "Enable automatic alt reference frames"); -static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1, - "AltRef Max Frames"); -static const arg_def_t arnr_strength = ARG_DEF(NULL, "arnr-strength", 1, - "AltRef Strength"); -static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1, - "AltRef Type"); -static const struct arg_enum_list tuning_enum[] = { - {"psnr", VP8_TUNE_PSNR}, - {"ssim", VP8_TUNE_SSIM}, - {NULL, 0} -}; -static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1, - "Material to favor", tuning_enum); -static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1, - "Constrained Quality Level"); -static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1, - "Max I-frame bitrate (pct)"); - -static const arg_def_t *vp8_args[] = -{ - &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, - &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type, - &tune_ssim, &cq_level, &max_intra_rate_pct, NULL -}; -static const int vp8_arg_ctrl_map[] = -{ - VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, - VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, - VP8E_SET_TOKEN_PARTITIONS, - VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH , VP8E_SET_ARNR_TYPE, - VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, 0 -}; -#endif - -static const arg_def_t *no_args[] = { NULL }; - -static void usage_exit() -{ - int i; - - fprintf(stderr, "Usage: %s -o dst_filename src_filename \n", - exec_name); - - fprintf(stderr, "\nOptions:\n"); - arg_show_usage(stdout, main_args); - fprintf(stderr, "\nEncoder Global Options:\n"); - arg_show_usage(stdout, global_args); - fprintf(stderr, "\nRate Control Options:\n"); - arg_show_usage(stdout, rc_args); - fprintf(stderr, "\nTwopass Rate Control Options:\n"); - arg_show_usage(stdout, rc_twopass_args); - fprintf(stderr, "\nKeyframe Placement Options:\n"); - arg_show_usage(stdout, kf_args); -#if CONFIG_VP8_ENCODER - fprintf(stderr, "\nVP8 Specific Options:\n"); - arg_show_usage(stdout, vp8_args); -#endif - fprintf(stderr, "\nStream timebase (--timebase):\n" - " The desired precision of timestamps in the output, expressed\n" - " in fractional seconds. Default is 1/1000.\n"); - fprintf(stderr, "\n" - "Included encoders:\n" - "\n"); - - for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++) - fprintf(stderr, " %-6s - %s\n", - codecs[i].name, - vpx_codec_iface_name(codecs[i].iface)); - - exit(EXIT_FAILURE); -} - - -#define HIST_BAR_MAX 40 -struct hist_bucket -{ - int low, high, count; -}; - - -static int merge_hist_buckets(struct hist_bucket *bucket, - int *buckets_, - int max_buckets) -{ - int small_bucket = 0, merge_bucket = INT_MAX, big_bucket=0; - int buckets = *buckets_; - int i; - - /* Find the extrema for this list of buckets */ - big_bucket = small_bucket = 0; - for(i=0; i < buckets; i++) - { - if(bucket[i].count < bucket[small_bucket].count) - small_bucket = i; - if(bucket[i].count > bucket[big_bucket].count) - big_bucket = i; - } - - /* If we have too many buckets, merge the smallest with an adjacent - * bucket. - */ - while(buckets > max_buckets) - { - int last_bucket = buckets - 1; - - // merge the small bucket with an adjacent one. - if(small_bucket == 0) - merge_bucket = 1; - else if(small_bucket == last_bucket) - merge_bucket = last_bucket - 1; - else if(bucket[small_bucket - 1].count < bucket[small_bucket + 1].count) - merge_bucket = small_bucket - 1; - else - merge_bucket = small_bucket + 1; - - assert(abs(merge_bucket - small_bucket) <= 1); - assert(small_bucket < buckets); - assert(big_bucket < buckets); - assert(merge_bucket < buckets); - - if(merge_bucket < small_bucket) - { - bucket[merge_bucket].high = bucket[small_bucket].high; - bucket[merge_bucket].count += bucket[small_bucket].count; - } - else - { - bucket[small_bucket].high = bucket[merge_bucket].high; - bucket[small_bucket].count += bucket[merge_bucket].count; - merge_bucket = small_bucket; - } - - assert(bucket[merge_bucket].low != bucket[merge_bucket].high); - - buckets--; - - /* Remove the merge_bucket from the list, and find the new small - * and big buckets while we're at it - */ - big_bucket = small_bucket = 0; - for(i=0; i < buckets; i++) - { - if(i > merge_bucket) - bucket[i] = bucket[i+1]; - - if(bucket[i].count < bucket[small_bucket].count) - small_bucket = i; - if(bucket[i].count > bucket[big_bucket].count) - big_bucket = i; - } - - } - - *buckets_ = buckets; - return bucket[big_bucket].count; -} - - -static void show_histogram(const struct hist_bucket *bucket, - int buckets, - int total, - int scale) -{ - const char *pat1, *pat2; - int i; - - switch((int)(log(bucket[buckets-1].high)/log(10))+1) - { - case 1: - case 2: - pat1 = "%4d %2s: "; - pat2 = "%4d-%2d: "; - break; - case 3: - pat1 = "%5d %3s: "; - pat2 = "%5d-%3d: "; - break; - case 4: - pat1 = "%6d %4s: "; - pat2 = "%6d-%4d: "; - break; - case 5: - pat1 = "%7d %5s: "; - pat2 = "%7d-%5d: "; - break; - case 6: - pat1 = "%8d %6s: "; - pat2 = "%8d-%6d: "; - break; - case 7: - pat1 = "%9d %7s: "; - pat2 = "%9d-%7d: "; - break; - default: - pat1 = "%12d %10s: "; - pat2 = "%12d-%10d: "; - break; - } - - for(i=0; isamples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000; - - // prevent division by zero - if (hist->samples == 0) - hist->samples=1; - - hist->pts = calloc(hist->samples, sizeof(*hist->pts)); - hist->sz = calloc(hist->samples, sizeof(*hist->sz)); - for(i=0; ibucket[i].low = INT_MAX; - hist->bucket[i].high = 0; - hist->bucket[i].count = 0; - } -} - - -static void destroy_rate_histogram(struct rate_hist *hist) -{ - free(hist->pts); - free(hist->sz); -} - - -static void update_rate_histogram(struct rate_hist *hist, - const vpx_codec_enc_cfg_t *cfg, - const vpx_codec_cx_pkt_t *pkt) -{ - int i, idx; - int64_t now, then, sum_sz = 0, avg_bitrate; - - now = pkt->data.frame.pts * 1000 - * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; - - idx = hist->frames++ % hist->samples; - hist->pts[idx] = now; - hist->sz[idx] = pkt->data.frame.sz; - - if(now < cfg->rc_buf_initial_sz) - return; - - then = now; - - /* Sum the size over the past rc_buf_sz ms */ - for(i = hist->frames; i > 0 && hist->frames - i < hist->samples; i--) - { - int i_idx = (i-1) % hist->samples; - - then = hist->pts[i_idx]; - if(now - then > cfg->rc_buf_sz) - break; - sum_sz += hist->sz[i_idx]; - } - - if (now == then) - return; - - avg_bitrate = sum_sz * 8 * 1000 / (now - then); - idx = avg_bitrate * (RATE_BINS/2) / (cfg->rc_target_bitrate * 1000); - if(idx < 0) - idx = 0; - if(idx > RATE_BINS-1) - idx = RATE_BINS-1; - if(hist->bucket[idx].low > avg_bitrate) - hist->bucket[idx].low = avg_bitrate; - if(hist->bucket[idx].high < avg_bitrate) - hist->bucket[idx].high = avg_bitrate; - hist->bucket[idx].count++; - hist->total++; -} - - -static void show_rate_histogram(struct rate_hist *hist, - const vpx_codec_enc_cfg_t *cfg, - int max_buckets) -{ - int i, scale; - int buckets = 0; - - for(i = 0; i < RATE_BINS; i++) - { - if(hist->bucket[i].low == INT_MAX) - continue; - hist->bucket[buckets++] = hist->bucket[i]; - } - - fprintf(stderr, "\nRate (over %dms window):\n", cfg->rc_buf_sz); - scale = merge_hist_buckets(hist->bucket, &buckets, max_buckets); - show_histogram(hist->bucket, buckets, hist->total, scale); -} - -#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) -#define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map) - - -/* Configuration elements common to all streams */ -struct global_config -{ - const struct codec_item *codec; - int passes; - int pass; - int usage; - int deadline; - int use_i420; - int verbose; - int limit; - int show_psnr; - int have_framerate; - struct vpx_rational framerate; - int out_part; - int debug; - int show_q_hist_buckets; - int show_rate_hist_buckets; -}; - - -/* Per-stream configuration */ -struct stream_config -{ - struct vpx_codec_enc_cfg cfg; - const char *out_fn; - const char *stats_fn; - stereo_format_t stereo_fmt; - int arg_ctrls[ARG_CTRL_CNT_MAX][2]; - int arg_ctrl_cnt; - int write_webm; - int have_kf_max_dist; -}; - - -struct stream_state -{ - int index; - struct stream_state *next; - struct stream_config config; - FILE *file; - struct rate_hist rate_hist; - EbmlGlobal ebml; - uint32_t hash; - uint64_t psnr_sse_total; - uint64_t psnr_samples_total; - double psnr_totals[4]; - int psnr_count; - int counts[64]; - vpx_codec_ctx_t encoder; - unsigned int frames_out; - uint64_t cx_time; - size_t nbytes; - stats_io_t stats; -}; - - -void validate_positive_rational(const char *msg, - struct vpx_rational *rat) -{ - if (rat->den < 0) - { - rat->num *= -1; - rat->den *= -1; - } - - if (rat->num < 0) - die("Error: %s must be positive\n", msg); - - if (!rat->den) - die("Error: %s has zero denominator\n", msg); -} - - -static void parse_global_config(struct global_config *global, char **argv) -{ - char **argi, **argj; - struct arg arg; - - /* Initialize default parameters */ - memset(global, 0, sizeof(*global)); - global->codec = codecs; - global->passes = 1; - global->use_i420 = 1; - - for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) - { - arg.argv_step = 1; - - if (arg_match(&arg, &codecarg, argi)) - { - int j, k = -1; - - for (j = 0; j < sizeof(codecs) / sizeof(codecs[0]); j++) - if (!strcmp(codecs[j].name, arg.val)) - k = j; - - if (k >= 0) - global->codec = codecs + k; - else - die("Error: Unrecognized argument (%s) to --codec\n", - arg.val); - - } - else if (arg_match(&arg, &passes, argi)) - { - global->passes = arg_parse_uint(&arg); - - if (global->passes < 1 || global->passes > 2) - die("Error: Invalid number of passes (%d)\n", global->passes); - } - else if (arg_match(&arg, &pass_arg, argi)) - { - global->pass = arg_parse_uint(&arg); - - if (global->pass < 1 || global->pass > 2) - die("Error: Invalid pass selected (%d)\n", - global->pass); - } - else if (arg_match(&arg, &usage, argi)) - global->usage = arg_parse_uint(&arg); - else if (arg_match(&arg, &deadline, argi)) - global->deadline = arg_parse_uint(&arg); - else if (arg_match(&arg, &best_dl, argi)) - global->deadline = VPX_DL_BEST_QUALITY; - else if (arg_match(&arg, &good_dl, argi)) - global->deadline = VPX_DL_GOOD_QUALITY; - else if (arg_match(&arg, &rt_dl, argi)) - global->deadline = VPX_DL_REALTIME; - else if (arg_match(&arg, &use_yv12, argi)) - global->use_i420 = 0; - else if (arg_match(&arg, &use_i420, argi)) - global->use_i420 = 1; - else if (arg_match(&arg, &verbosearg, argi)) - global->verbose = 1; - else if (arg_match(&arg, &limit, argi)) - global->limit = arg_parse_uint(&arg); - else if (arg_match(&arg, &psnrarg, argi)) - global->show_psnr = 1; - else if (arg_match(&arg, &framerate, argi)) - { - global->framerate = arg_parse_rational(&arg); - validate_positive_rational(arg.name, &global->framerate); - global->have_framerate = 1; - } - else if (arg_match(&arg,&out_part, argi)) - global->out_part = 1; - else if (arg_match(&arg, &debugmode, argi)) - global->debug = 1; - else if (arg_match(&arg, &q_hist_n, argi)) - global->show_q_hist_buckets = arg_parse_uint(&arg); - else if (arg_match(&arg, &rate_hist_n, argi)) - global->show_rate_hist_buckets = arg_parse_uint(&arg); - else - argj++; - } - - /* Validate global config */ - - if (global->pass) - { - /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ - if (global->pass > global->passes) - { - warn("Assuming --pass=%d implies --passes=%d\n", - global->pass, global->pass); - global->passes = global->pass; - } - } -} - - -void open_input_file(struct input_state *input, struct global_config *global) -{ - unsigned int fourcc; - - /* Parse certain options from the input file, if possible */ - input->file = strcmp(input->fn, "-") ? fopen(input->fn, "rb") - : set_binary_mode(stdin); - - if (!input->file) - fatal("Failed to open input file"); - - /* For RAW input sources, these bytes will applied on the first frame - * in read_frame(). - */ - input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file); - input->detect.position = 0; - - if (input->detect.buf_read == 4 - && file_is_y4m(input->file, &input->y4m, input->detect.buf)) - { - if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4) >= 0) - { - input->file_type = FILE_TYPE_Y4M; - input->w = input->y4m.pic_w; - input->h = input->y4m.pic_h; - input->framerate.num = input->y4m.fps_n; - input->framerate.den = input->y4m.fps_d; - input->use_i420 = 0; - } - else - fatal("Unsupported Y4M stream."); - } - else if (input->detect.buf_read == 4 && file_is_ivf(input, &fourcc)) - { - input->file_type = FILE_TYPE_IVF; - switch (fourcc) - { - case 0x32315659: - input->use_i420 = 0; - break; - case 0x30323449: - input->use_i420 = 1; - break; - default: - fatal("Unsupported fourcc (%08x) in IVF", fourcc); - } - } - else if (input->detect.buf_read == 4 && file_is_wcap(input)) - { - input->wcap = wcap_decoder_create(input->fn); - - input->file_type = FILE_TYPE_WCAP; - input->w = input->wcap->width; - input->h = input->wcap->height; - input->use_i420 = 0; - if (global->have_framerate) { - input->framerate = global->framerate; - } - else { - input->framerate.num = 30; - input->framerate.den = 1; - } - } - else - { - input->file_type = FILE_TYPE_RAW; - } -} - - -static void close_input_file(struct input_state *input) -{ - fclose(input->file); - if (input->file_type == FILE_TYPE_Y4M) - y4m_input_close(&input->y4m); - else if (input->file_type == FILE_TYPE_WCAP) - wcap_decoder_destroy(input->wcap); -} - -static struct stream_state *new_stream(struct global_config *global, - struct stream_state *prev) -{ - struct stream_state *stream; - - stream = calloc(1, sizeof(*stream)); - if(!stream) - fatal("Failed to allocate new stream."); - if(prev) - { - memcpy(stream, prev, sizeof(*stream)); - stream->index++; - prev->next = stream; - } - else - { - vpx_codec_err_t res; - - /* Populate encoder configuration */ - res = vpx_codec_enc_config_default(global->codec->iface, - &stream->config.cfg, - global->usage); - if (res) - fatal("Failed to get config: %s\n", vpx_codec_err_to_string(res)); - - /* Change the default timebase to a high enough value so that the - * encoder will always create strictly increasing timestamps. - */ - stream->config.cfg.g_timebase.den = 1000; - - /* Never use the library's default resolution, require it be parsed - * from the file or set on the command line. - */ - stream->config.cfg.g_w = 0; - stream->config.cfg.g_h = 0; - - /* Initialize remaining stream parameters */ - stream->config.stereo_fmt = STEREO_FORMAT_MONO; - stream->config.write_webm = 1; - stream->ebml.last_pts_ms = -1; - - /* Allows removal of the application version from the EBML tags */ - stream->ebml.debug = global->debug; - } - - /* Output files must be specified for each stream */ - stream->config.out_fn = NULL; - - stream->next = NULL; - return stream; -} - - -static int parse_stream_params(struct global_config *global, - struct stream_state *stream, - char **argv) -{ - char **argi, **argj; - struct arg arg; - static const arg_def_t **ctrl_args = no_args; - static const int *ctrl_args_map = NULL; - struct stream_config *config = &stream->config; - int eos_mark_found = 0; - - /* Handle codec specific options */ - if (global->codec->iface == &vpx_codec_vp8_cx_algo) - { - ctrl_args = vp8_args; - ctrl_args_map = vp8_arg_ctrl_map; - } - - for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) - { - arg.argv_step = 1; - - /* Once we've found an end-of-stream marker (--) we want to continue - * shifting arguments but not consuming them. - */ - if (eos_mark_found) - { - argj++; - continue; - } - else if (!strcmp(*argj, "--")) - { - eos_mark_found = 1; - continue; - } - - if (0); - else if (arg_match(&arg, &outputfile, argi)) - config->out_fn = arg.val; - else if (arg_match(&arg, &fpf_name, argi)) - config->stats_fn = arg.val; - else if (arg_match(&arg, &use_ivf, argi)) - config->write_webm = 0; - else if (arg_match(&arg, &threads, argi)) - config->cfg.g_threads = arg_parse_uint(&arg); - else if (arg_match(&arg, &profile, argi)) - config->cfg.g_profile = arg_parse_uint(&arg); - else if (arg_match(&arg, &width, argi)) - config->cfg.g_w = arg_parse_uint(&arg); - else if (arg_match(&arg, &height, argi)) - config->cfg.g_h = arg_parse_uint(&arg); - else if (arg_match(&arg, &stereo_mode, argi)) - config->stereo_fmt = arg_parse_enum_or_int(&arg); - else if (arg_match(&arg, &timebase, argi)) - { - config->cfg.g_timebase = arg_parse_rational(&arg); - validate_positive_rational(arg.name, &config->cfg.g_timebase); - } - else if (arg_match(&arg, &error_resilient, argi)) - config->cfg.g_error_resilient = arg_parse_uint(&arg); - else if (arg_match(&arg, &lag_in_frames, argi)) - config->cfg.g_lag_in_frames = arg_parse_uint(&arg); - else if (arg_match(&arg, &dropframe_thresh, argi)) - config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg); - else if (arg_match(&arg, &resize_allowed, argi)) - config->cfg.rc_resize_allowed = arg_parse_uint(&arg); - else if (arg_match(&arg, &resize_up_thresh, argi)) - config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg); - else if (arg_match(&arg, &resize_down_thresh, argi)) - config->cfg.rc_resize_down_thresh = arg_parse_uint(&arg); - else if (arg_match(&arg, &end_usage, argi)) - config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg); - else if (arg_match(&arg, &target_bitrate, argi)) - config->cfg.rc_target_bitrate = arg_parse_uint(&arg); - else if (arg_match(&arg, &min_quantizer, argi)) - config->cfg.rc_min_quantizer = arg_parse_uint(&arg); - else if (arg_match(&arg, &max_quantizer, argi)) - config->cfg.rc_max_quantizer = arg_parse_uint(&arg); - else if (arg_match(&arg, &undershoot_pct, argi)) - config->cfg.rc_undershoot_pct = arg_parse_uint(&arg); - else if (arg_match(&arg, &overshoot_pct, argi)) - config->cfg.rc_overshoot_pct = arg_parse_uint(&arg); - else if (arg_match(&arg, &buf_sz, argi)) - config->cfg.rc_buf_sz = arg_parse_uint(&arg); - else if (arg_match(&arg, &buf_initial_sz, argi)) - config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg); - else if (arg_match(&arg, &buf_optimal_sz, argi)) - config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg); - else if (arg_match(&arg, &bias_pct, argi)) - { - config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg); - - if (global->passes < 2) - warn("option %s ignored in one-pass mode.\n", arg.name); - } - else if (arg_match(&arg, &minsection_pct, argi)) - { - config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg); - - if (global->passes < 2) - warn("option %s ignored in one-pass mode.\n", arg.name); - } - else if (arg_match(&arg, &maxsection_pct, argi)) - { - config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg); - - if (global->passes < 2) - warn("option %s ignored in one-pass mode.\n", arg.name); - } - else if (arg_match(&arg, &kf_min_dist, argi)) - config->cfg.kf_min_dist = arg_parse_uint(&arg); - else if (arg_match(&arg, &kf_max_dist, argi)) - { - config->cfg.kf_max_dist = arg_parse_uint(&arg); - config->have_kf_max_dist = 1; - } - else if (arg_match(&arg, &kf_disabled, argi)) - config->cfg.kf_mode = VPX_KF_DISABLED; - else - { - int i, match = 0; - - for (i = 0; ctrl_args[i]; i++) - { - if (arg_match(&arg, ctrl_args[i], argi)) - { - int j; - match = 1; - - /* Point either to the next free element or the first - * instance of this control. - */ - for(j=0; jarg_ctrl_cnt; j++) - if(config->arg_ctrls[j][0] == ctrl_args_map[i]) - break; - - /* Update/insert */ - assert(j < ARG_CTRL_CNT_MAX); - if (j < ARG_CTRL_CNT_MAX) - { - config->arg_ctrls[j][0] = ctrl_args_map[i]; - config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg); - if(j == config->arg_ctrl_cnt) - config->arg_ctrl_cnt++; - } - - } - } - - if (!match) - argj++; - } - } - - return eos_mark_found; -} - - -#define FOREACH_STREAM(func)\ -do\ -{\ - struct stream_state *stream;\ -\ - for(stream = streams; stream; stream = stream->next)\ - func;\ -}while(0) - - -static void validate_stream_config(struct stream_state *stream) -{ - struct stream_state *streami; - - if(!stream->config.cfg.g_w || !stream->config.cfg.g_h) - fatal("Stream %d: Specify stream dimensions with --width (-w) " - " and --height (-h)", stream->index); - - for(streami = stream; streami; streami = streami->next) - { - /* All streams require output files */ - if(!streami->config.out_fn) - fatal("Stream %d: Output file is required (specify with -o)", - streami->index); - - /* Check for two streams outputting to the same file */ - if(streami != stream) - { - const char *a = stream->config.out_fn; - const char *b = streami->config.out_fn; - if(!strcmp(a,b) && strcmp(a, "/dev/null") && strcmp(a, ":nul")) - fatal("Stream %d: duplicate output file (from stream %d)", - streami->index, stream->index); - } - - /* Check for two streams sharing a stats file. */ - if(streami != stream) - { - const char *a = stream->config.stats_fn; - const char *b = streami->config.stats_fn; - if(a && b && !strcmp(a,b)) - fatal("Stream %d: duplicate stats file (from stream %d)", - streami->index, stream->index); - } - } -} - - -static void set_stream_dimensions(struct stream_state *stream, - unsigned int w, - unsigned int h) -{ - if ((stream->config.cfg.g_w && stream->config.cfg.g_w != w) - ||(stream->config.cfg.g_h && stream->config.cfg.g_h != h)) - fatal("Stream %d: Resizing not yet supported", stream->index); - stream->config.cfg.g_w = w; - stream->config.cfg.g_h = h; -} - - -static void set_default_kf_interval(struct stream_state *stream, - struct global_config *global) -{ - /* Use a max keyframe interval of 5 seconds, if none was - * specified on the command line. - */ - if (!stream->config.have_kf_max_dist) - { - double framerate = (double)global->framerate.num/global->framerate.den; - if (framerate > 0.0) - stream->config.cfg.kf_max_dist = 5.0*framerate; - } -} - - -static void show_stream_config(struct stream_state *stream, - struct global_config *global, - struct input_state *input) -{ - -#define SHOW(field) \ - fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) - - if(stream->index == 0) - { - fprintf(stderr, "Codec: %s\n", - vpx_codec_iface_name(global->codec->iface)); - fprintf(stderr, "Source file: %s Format: %s\n", input->fn, - input->use_i420 ? "I420" : "YV12"); - } - if(stream->next || stream->index) - fprintf(stderr, "\nStream Index: %d\n", stream->index); - fprintf(stderr, "Destination file: %s\n", stream->config.out_fn); - fprintf(stderr, "Encoder parameters:\n"); - - SHOW(g_usage); - SHOW(g_threads); - SHOW(g_profile); - SHOW(g_w); - SHOW(g_h); - SHOW(g_timebase.num); - SHOW(g_timebase.den); - SHOW(g_error_resilient); - SHOW(g_pass); - SHOW(g_lag_in_frames); - SHOW(rc_dropframe_thresh); - SHOW(rc_resize_allowed); - SHOW(rc_resize_up_thresh); - SHOW(rc_resize_down_thresh); - SHOW(rc_end_usage); - SHOW(rc_target_bitrate); - SHOW(rc_min_quantizer); - SHOW(rc_max_quantizer); - SHOW(rc_undershoot_pct); - SHOW(rc_overshoot_pct); - SHOW(rc_buf_sz); - SHOW(rc_buf_initial_sz); - SHOW(rc_buf_optimal_sz); - SHOW(rc_2pass_vbr_bias_pct); - SHOW(rc_2pass_vbr_minsection_pct); - SHOW(rc_2pass_vbr_maxsection_pct); - SHOW(kf_mode); - SHOW(kf_min_dist); - SHOW(kf_max_dist); -} - - -static void open_output_file(struct stream_state *stream, - struct global_config *global) -{ - const char *fn = stream->config.out_fn; - - stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout); - - if (!stream->file) - fatal("Failed to open output file"); - - if(stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR)) - fatal("WebM output to pipes not supported."); - - if(stream->config.write_webm) - { - stream->ebml.stream = stream->file; - write_webm_file_header(&stream->ebml, &stream->config.cfg, - &global->framerate, - stream->config.stereo_fmt); - } - else - write_ivf_file_header(stream->file, &stream->config.cfg, - global->codec->fourcc, 0); -} - - -static void close_output_file(struct stream_state *stream, - unsigned int fourcc) -{ - if(stream->config.write_webm) - { - write_webm_file_footer(&stream->ebml, stream->hash); - free(stream->ebml.cue_list); - stream->ebml.cue_list = NULL; - } - else - { - if (!fseek(stream->file, 0, SEEK_SET)) - write_ivf_file_header(stream->file, &stream->config.cfg, - fourcc, - stream->frames_out); - } - - fclose(stream->file); -} - - -static void setup_pass(struct stream_state *stream, - struct global_config *global, - int pass) -{ - if (stream->config.stats_fn) - { - if (!stats_open_file(&stream->stats, stream->config.stats_fn, - pass)) - fatal("Failed to open statistics store"); - } - else - { - if (!stats_open_mem(&stream->stats, pass)) - fatal("Failed to open statistics store"); - } - - stream->config.cfg.g_pass = global->passes == 2 - ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS - : VPX_RC_ONE_PASS; - if (pass) - stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); - - stream->cx_time = 0; - stream->nbytes = 0; - stream->frames_out = 0; -} - - -static void initialize_encoder(struct stream_state *stream, - struct global_config *global) -{ - int i; - int flags = 0; - - flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0; - flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0; - - /* Construct Encoder Context */ - vpx_codec_enc_init(&stream->encoder, global->codec->iface, - &stream->config.cfg, flags); - ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder"); - - /* Note that we bypass the vpx_codec_control wrapper macro because - * we're being clever to store the control IDs in an array. Real - * applications will want to make use of the enumerations directly - */ - for (i = 0; i < stream->config.arg_ctrl_cnt; i++) - { - int ctrl = stream->config.arg_ctrls[i][0]; - int value = stream->config.arg_ctrls[i][1]; - if (vpx_codec_control_(&stream->encoder, ctrl, value)) - fprintf(stderr, "Error: Tried to set control %d = %d\n", - ctrl, value); - - ctx_exit_on_error(&stream->encoder, "Failed to control codec"); - } -} - - -static void encode_frame(struct stream_state *stream, - struct global_config *global, - struct vpx_image *img, - unsigned int frames_in) -{ - vpx_codec_pts_t frame_start, next_frame_start; - struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; - struct vpx_usec_timer timer; - - frame_start = (cfg->g_timebase.den * (int64_t)(frames_in - 1) - * global->framerate.den) - / cfg->g_timebase.num / global->framerate.num; - next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in) - * global->framerate.den) - / cfg->g_timebase.num / global->framerate.num; - vpx_usec_timer_start(&timer); - vpx_codec_encode(&stream->encoder, img, frame_start, - next_frame_start - frame_start, - 0, global->deadline); - vpx_usec_timer_mark(&timer); - stream->cx_time += vpx_usec_timer_elapsed(&timer); - ctx_exit_on_error(&stream->encoder, "Stream %d: Failed to encode frame", - stream->index); -} - - -static void update_quantizer_histogram(struct stream_state *stream) -{ - if(stream->config.cfg.g_pass != VPX_RC_FIRST_PASS) - { - int q; - - vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q); - ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); - stream->counts[q]++; - } -} - - -static void get_cx_data(struct stream_state *stream, - struct global_config *global, - int *got_data) -{ - const vpx_codec_cx_pkt_t *pkt; - const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; - vpx_codec_iter_t iter = NULL; - - while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) - { - static size_t fsize = 0; - static off_t ivf_header_pos = 0; - - *got_data = 1; - - switch (pkt->kind) - { - case VPX_CODEC_CX_FRAME_PKT: - if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) - { - stream->frames_out++; - } - fprintf(stderr, " %6luF", - (unsigned long)pkt->data.frame.sz); - - update_rate_histogram(&stream->rate_hist, cfg, pkt); - if(stream->config.write_webm) - { - /* Update the hash */ - if(!stream->ebml.debug) - stream->hash = murmur(pkt->data.frame.buf, - pkt->data.frame.sz, stream->hash); - - write_webm_block(&stream->ebml, cfg, pkt); - } - else - { - if (pkt->data.frame.partition_id <= 0) - { - ivf_header_pos = ftello(stream->file); - fsize = pkt->data.frame.sz; - - write_ivf_frame_header(stream->file, pkt); - } - else - { - fsize += pkt->data.frame.sz; - - if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) - { - off_t currpos = ftello(stream->file); - fseeko(stream->file, ivf_header_pos, SEEK_SET); - write_ivf_frame_size(stream->file, fsize); - fseeko(stream->file, currpos, SEEK_SET); - } - } - - fwrite(pkt->data.frame.buf, 1, - pkt->data.frame.sz, stream->file); - } - stream->nbytes += pkt->data.raw.sz; - break; - case VPX_CODEC_STATS_PKT: - stream->frames_out++; - fprintf(stderr, " %6luS", - (unsigned long)pkt->data.twopass_stats.sz); - stats_write(&stream->stats, - pkt->data.twopass_stats.buf, - pkt->data.twopass_stats.sz); - stream->nbytes += pkt->data.raw.sz; - break; - case VPX_CODEC_PSNR_PKT: - - if (global->show_psnr) - { - int i; - - stream->psnr_sse_total += pkt->data.psnr.sse[0]; - stream->psnr_samples_total += pkt->data.psnr.samples[0]; - for (i = 0; i < 4; i++) - { - fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]); - stream->psnr_totals[i] += pkt->data.psnr.psnr[i]; - } - stream->psnr_count++; - } - - break; - default: - break; - } - } -} - - -static void show_psnr(struct stream_state *stream) -{ - int i; - double ovpsnr; - - if (!stream->psnr_count) - return; - - fprintf(stderr, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream->index); - ovpsnr = vp8_mse2psnr(stream->psnr_samples_total, 255.0, - stream->psnr_sse_total); - fprintf(stderr, " %.3lf", ovpsnr); - - for (i = 0; i < 4; i++) - { - fprintf(stderr, " %.3lf", stream->psnr_totals[i]/stream->psnr_count); - } - fprintf(stderr, "\n"); -} - - -float usec_to_fps(uint64_t usec, unsigned int frames) -{ - return usec > 0 ? (float)frames * 1000000.0 / (float)usec : 0; -} - - -int main(int argc, const char **argv_) -{ - int pass; - vpx_image_t raw; - int frame_avail, got_data; - - struct input_state input = {0}; - struct global_config global; - struct stream_state *streams = NULL; - char **argv, **argi; - unsigned long cx_time = 0; - int stream_cnt = 0; - - exec_name = argv_[0]; - - if (argc < 3) - usage_exit(); - - /* Setup default input stream settings */ - input.framerate.num = 30; - input.framerate.den = 1; - input.use_i420 = 1; - - /* First parse the global configuration values, because we want to apply - * other parameters on top of the default configuration provided by the - * codec. - */ - argv = argv_dup(argc - 1, argv_ + 1); - parse_global_config(&global, argv); - - { - /* Now parse each stream's parameters. Using a local scope here - * due to the use of 'stream' as loop variable in FOREACH_STREAM - * loops - */ - struct stream_state *stream = NULL; - - do - { - stream = new_stream(&global, stream); - stream_cnt++; - if(!streams) - streams = stream; - } while(parse_stream_params(&global, stream, argv)); - } - - /* Check for unrecognized options */ - for (argi = argv; *argi; argi++) - if (argi[0][0] == '-' && argi[0][1]) - die("Error: Unrecognized option %s\n", *argi); - - /* Handle non-option arguments */ - input.fn = argv[0]; - - if (!input.fn) - usage_exit(); - - for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) - { - int frames_in = 0; - - open_input_file(&input, &global); - - /* If the input file doesn't specify its w/h (raw files), try to get - * the data from the first stream's configuration. - */ - if(!input.w || !input.h) - FOREACH_STREAM({ - if(stream->config.cfg.g_w && stream->config.cfg.g_h) - { - input.w = stream->config.cfg.g_w; - input.h = stream->config.cfg.g_h; - break; - } - }); - - /* Update stream configurations from the input file's parameters */ - FOREACH_STREAM(set_stream_dimensions(stream, input.w, input.h)); - FOREACH_STREAM(validate_stream_config(stream)); - - /* Ensure that --passes and --pass are consistent. If --pass is set and - * --passes=2, ensure --fpf was set. - */ - if (global.pass && global.passes == 2) - FOREACH_STREAM({ - if(!stream->config.stats_fn) - die("Stream %d: Must specify --fpf when --pass=%d" - " and --passes=2\n", stream->index, global.pass); - }); - - - /* Use the frame rate from the file only if none was specified - * on the command-line. - */ - if (!global.have_framerate) - global.framerate = input.framerate; - - FOREACH_STREAM(set_default_kf_interval(stream, &global)); - - /* Show configuration */ - if (global.verbose && pass == 0) - FOREACH_STREAM(show_stream_config(stream, &global, &input)); - - if(pass == (global.pass ? global.pass - 1 : 0)) { - if (input.file_type == FILE_TYPE_Y4M) - /*The Y4M reader does its own allocation. - Just initialize this here to avoid problems if we never read any - frames.*/ - memset(&raw, 0, sizeof(raw)); - else - vpx_img_alloc(&raw, - input.use_i420 ? VPX_IMG_FMT_I420 - : VPX_IMG_FMT_YV12, - input.w, input.h, 32); - - FOREACH_STREAM(init_rate_histogram(&stream->rate_hist, - &stream->config.cfg, - &global.framerate)); - } - - FOREACH_STREAM(open_output_file(stream, &global)); - FOREACH_STREAM(setup_pass(stream, &global, pass)); - FOREACH_STREAM(initialize_encoder(stream, &global)); - - frame_avail = 1; - got_data = 0; - - while (frame_avail || got_data) - { - struct vpx_usec_timer timer; - - if (!global.limit || frames_in < global.limit) - { - frame_avail = read_frame(&input, &raw); - - if (frame_avail) - frames_in++; - - if(stream_cnt == 1) - fprintf(stderr, - "\rPass %d/%d frame %4d/%-4d %7"PRId64"B \033[K", - pass + 1, global.passes, frames_in, - streams->frames_out, (int64_t)streams->nbytes); - else - fprintf(stderr, - "\rPass %d/%d frame %4d %7lu %s (%.2f fps)\033[K", - pass + 1, global.passes, frames_in, - cx_time > 9999999 ? cx_time / 1000 : cx_time, - cx_time > 9999999 ? "ms" : "us", - usec_to_fps(cx_time, frames_in)); - - } - else - frame_avail = 0; - - vpx_usec_timer_start(&timer); - FOREACH_STREAM(encode_frame(stream, &global, - frame_avail ? &raw : NULL, - frames_in)); - vpx_usec_timer_mark(&timer); - cx_time += vpx_usec_timer_elapsed(&timer); - - FOREACH_STREAM(update_quantizer_histogram(stream)); - - got_data = 0; - FOREACH_STREAM(get_cx_data(stream, &global, &got_data)); - - fflush(stdout); - } - - if(stream_cnt > 1) - fprintf(stderr, "\n"); - - FOREACH_STREAM(fprintf( - stderr, - "\rPass %d/%d frame %4d/%-4d %7"PRId64"B %7lub/f %7"PRId64"b/s" - " %7"PRId64" %s (%.2f fps)\033[K\n", pass + 1, - global.passes, frames_in, stream->frames_out, (int64_t)stream->nbytes, - frames_in ? (unsigned long)(stream->nbytes * 8 / frames_in) : 0, - frames_in ? (int64_t)stream->nbytes * 8 - * (int64_t)global.framerate.num / global.framerate.den - / frames_in - : 0, - stream->cx_time > 9999999 ? stream->cx_time / 1000 : stream->cx_time, - stream->cx_time > 9999999 ? "ms" : "us", - usec_to_fps(stream->cx_time, frames_in)); - ); - - if (global.show_psnr) - FOREACH_STREAM(show_psnr(stream)); - - FOREACH_STREAM(vpx_codec_destroy(&stream->encoder)); - - close_input_file(&input); - - FOREACH_STREAM(close_output_file(stream, global.codec->fourcc)); - - FOREACH_STREAM(stats_close(&stream->stats, global.passes-1)); - - if (global.pass) - break; - } - - if (global.show_q_hist_buckets) - FOREACH_STREAM(show_q_histogram(stream->counts, - global.show_q_hist_buckets)); - - if (global.show_rate_hist_buckets) - FOREACH_STREAM(show_rate_histogram(&stream->rate_hist, - &stream->config.cfg, - global.show_rate_hist_buckets)); - FOREACH_STREAM(destroy_rate_histogram(&stream->rate_hist)); - - vpx_img_free(&raw); - free(argv); - free(streams); - return EXIT_SUCCESS; -} diff --git a/wcap/wcap-snapshot.c b/wcap/wcap-snapshot.c deleted file mode 100644 index 01df7a2..0000000 --- a/wcap/wcap-snapshot.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright © 2012 Intel Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of the copyright holders not be used in - * advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. The copyright holders make - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF - * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "wcap-decode.h" - -static void -write_png(struct wcap_decoder *decoder, const char *filename) -{ - cairo_surface_t *surface; - - surface = cairo_image_surface_create_for_data((unsigned char *) decoder->frame, - CAIRO_FORMAT_ARGB32, - decoder->width, - decoder->height, - decoder->width * 4); - cairo_surface_write_to_png(surface, filename); - cairo_surface_destroy(surface); -} - -int main(int argc, char *argv[]) -{ - struct wcap_decoder *decoder; - int i, output_frame; - char filename[200]; - - if (argc != 2 && argc != 3) { - fprintf(stderr, "usage: wcap-snapshot WCAP_FILE [FRAME]\n"); - return 1; - } - - decoder = wcap_decoder_create(argv[1]); - output_frame = -1; - if (argc == 3) - output_frame = strtol(argv[2], NULL, 0); - - i = 0; - while (wcap_decoder_get_frame(decoder)) { - if (i == output_frame) { - snprintf(filename, sizeof filename, - "wcap-frame-%d.png", i); - write_png(decoder, filename); - printf("wrote %s\n", filename); - } - i++; - } - - printf("wcap file: size %dx%d, %d frames\n", - decoder->width, decoder->height, i); - - wcap_decoder_destroy(decoder); - return EXIT_SUCCESS; -} diff --git a/wcap/y4minput.c b/wcap/y4minput.c deleted file mode 100644 index dd51421..0000000 --- a/wcap/y4minput.c +++ /dev/null @@ -1,871 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - * - * Based on code from the OggTheora software codec source code, - * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors. - */ -#include -#include -#include "y4minput.h" - -static int y4m_parse_tags(y4m_input *_y4m,char *_tags){ - int got_w; - int got_h; - int got_fps; - int got_interlace; - int got_par; - int got_chroma; - char *p; - char *q; - got_w=got_h=got_fps=got_interlace=got_par=got_chroma=0; - for(p=_tags;;p=q){ - /*Skip any leading spaces.*/ - while(*p==' ')p++; - /*If that's all we have, stop.*/ - if(p[0]=='\0')break; - /*Find the end of this tag.*/ - for(q=p+1;*q!='\0'&&*q!=' ';q++); - /*Process the tag.*/ - switch(p[0]){ - case 'W':{ - if(sscanf(p+1,"%d",&_y4m->pic_w)!=1)return -1; - got_w=1; - }break; - case 'H':{ - if(sscanf(p+1,"%d",&_y4m->pic_h)!=1)return -1; - got_h=1; - }break; - case 'F':{ - if(sscanf(p+1,"%d:%d",&_y4m->fps_n,&_y4m->fps_d)!=2){ - return -1; - } - got_fps=1; - }break; - case 'I':{ - _y4m->interlace=p[1]; - got_interlace=1; - }break; - case 'A':{ - if(sscanf(p+1,"%d:%d",&_y4m->par_n,&_y4m->par_d)!=2){ - return -1; - } - got_par=1; - }break; - case 'C':{ - if(q-p>16)return -1; - memcpy(_y4m->chroma_type,p+1,q-p-1); - _y4m->chroma_type[q-p-1]='\0'; - got_chroma=1; - }break; - /*Ignore unknown tags.*/ - } - } - if(!got_w||!got_h||!got_fps)return -1; - if(!got_interlace)_y4m->interlace='?'; - if(!got_par)_y4m->par_n=_y4m->par_d=0; - /*Chroma-type is not specified in older files, e.g., those generated by - mplayer.*/ - if(!got_chroma)strcpy(_y4m->chroma_type,"420"); - return 0; -} - - - -/*All anti-aliasing filters in the following conversion functions are based on - one of two window functions: - The 6-tap Lanczos window (for down-sampling and shifts): - sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t) - 0, |t|>=3 - The 4-tap Mitchell window (for up-sampling): - 7|t|^3-12|t|^2+16/3, |t|<1 - -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2 - 0, |t|>=2 - The number of taps is intentionally kept small to reduce computational - overhead and limit ringing. - - The taps from these filters are scaled so that their sum is 1, and the result - is scaled by 128 and rounded to integers to create a filter whose - intermediate values fit inside 16 bits. - Coefficients are rounded in such a way as to ensure their sum is still 128, - which is usually equivalent to normal rounding. - - Conversions which require both horizontal and vertical filtering could - have these steps pipelined, for less memory consumption and better cache - performance, but we do them separately for simplicity.*/ - -#define OC_MINI(_a,_b) ((_a)>(_b)?(_b):(_a)) -#define OC_MAXI(_a,_b) ((_a)<(_b)?(_b):(_a)) -#define OC_CLAMPI(_a,_b,_c) (OC_MAXI(_a,OC_MINI(_b,_c))) - -/*420jpeg chroma samples are sited like: - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - - 420mpeg2 chroma samples are sited like: - Y-------Y-------Y-------Y------- - | | | | - BR | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - Y-------Y-------Y-------Y------- - | | | | - BR | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - - We use a resampling filter to shift the site locations one quarter pixel (at - the chroma plane's resolution) to the right. - The 4:2:2 modes look exactly the same, except there are twice as many chroma - lines, and they are vertically co-sited with the luma samples in both the - mpeg2 and jpeg cases (thus requiring no vertical resampling).*/ -static void y4m_42xmpeg2_42xjpeg_helper(unsigned char *_dst, - const unsigned char *_src,int _c_w,int _c_h){ - int y; - int x; - for(y=0;y<_c_h;y++){ - /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos - window.*/ - for(x=0;x>7,255); - } - for(;x<_c_w-3;x++){ - _dst[x]=(unsigned char)OC_CLAMPI(0,(4*_src[x-2]-17*_src[x-1]+ - 114*_src[x]+35*_src[x+1]-9*_src[x+2]+_src[x+3]+64)>>7,255); - } - for(;x<_c_w;x++){ - _dst[x]=(unsigned char)OC_CLAMPI(0,(4*_src[x-2]-17*_src[x-1]+ - 114*_src[x]+35*_src[OC_MINI(x+1,_c_w-1)]-9*_src[OC_MINI(x+2,_c_w-1)]+ - _src[_c_w-1]+64)>>7,255); - } - _dst+=_c_w; - _src+=_c_w; - } -} - -/*Handles both 422 and 420mpeg2 to 422jpeg and 420jpeg, respectively.*/ -static void y4m_convert_42xmpeg2_42xjpeg(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ - int c_w; - int c_h; - int c_sz; - int pli; - /*Skip past the luma data.*/ - _dst+=_y4m->pic_w*_y4m->pic_h; - /*Compute the size of each chroma plane.*/ - c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; - c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; - c_sz=c_w*c_h; - for(pli=1;pli<3;pli++){ - y4m_42xmpeg2_42xjpeg_helper(_dst,_aux,c_w,c_h); - _dst+=c_sz; - _aux+=c_sz; - } -} - -/*This format is only used for interlaced content, but is included for - completeness. - - 420jpeg chroma samples are sited like: - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - - 420paldv chroma samples are sited like: - YR------Y-------YR------Y------- - | | | | - | | | | - | | | | - YB------Y-------YB------Y------- - | | | | - | | | | - | | | | - YR------Y-------YR------Y------- - | | | | - | | | | - | | | | - YB------Y-------YB------Y------- - | | | | - | | | | - | | | | - - We use a resampling filter to shift the site locations one quarter pixel (at - the chroma plane's resolution) to the right. - Then we use another filter to move the C_r location down one quarter pixel, - and the C_b location up one quarter pixel.*/ -static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ - unsigned char *tmp; - int c_w; - int c_h; - int c_sz; - int pli; - int y; - int x; - /*Skip past the luma data.*/ - _dst+=_y4m->pic_w*_y4m->pic_h; - /*Compute the size of each chroma plane.*/ - c_w=(_y4m->pic_w+1)/2; - c_h=(_y4m->pic_h+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; - c_sz=c_w*c_h; - tmp=_aux+2*c_sz; - for(pli=1;pli<3;pli++){ - /*First do the horizontal re-sampling. - This is the same as the mpeg2 case, except that after the horizontal - case, we need to apply a second vertical filter.*/ - y4m_42xmpeg2_42xjpeg_helper(tmp,_aux,c_w,c_h); - _aux+=c_sz; - switch(pli){ - case 1:{ - /*Slide C_b up a quarter-pel. - This is the same filter used above, but in the other order.*/ - for(x=0;x>7,255); - } - for(;y>7,255); - } - for(;y>7,255); - } - _dst++; - tmp++; - } - _dst+=c_sz-c_w; - tmp-=c_w; - }break; - case 2:{ - /*Slide C_r down a quarter-pel. - This is the same as the horizontal filter.*/ - for(x=0;x>7,255); - } - for(;y>7,255); - } - for(;y>7,255); - } - _dst++; - tmp++; - } - }break; - } - /*For actual interlaced material, this would have to be done separately on - each field, and the shift amounts would be different. - C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8, - C_b up 1/8 in the bottom field. - The corresponding filters would be: - Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128 - Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/ - } -} - -/*Perform vertical filtering to reduce a single plane from 4:2:2 to 4:2:0. - This is used as a helper by several converation routines.*/ -static void y4m_422jpeg_420jpeg_helper(unsigned char *_dst, - const unsigned char *_src,int _c_w,int _c_h){ - int y; - int x; - /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/ - for(x=0;x<_c_w;x++){ - for(y=0;y>1)*_c_w]=OC_CLAMPI(0,(64*_src[0] - +78*_src[OC_MINI(1,_c_h-1)*_c_w] - -17*_src[OC_MINI(2,_c_h-1)*_c_w] - +3*_src[OC_MINI(3,_c_h-1)*_c_w]+64)>>7,255); - } - for(;y<_c_h-3;y+=2){ - _dst[(y>>1)*_c_w]=OC_CLAMPI(0,(3*(_src[(y-2)*_c_w]+_src[(y+3)*_c_w]) - -17*(_src[(y-1)*_c_w]+_src[(y+2)*_c_w]) - +78*(_src[y*_c_w]+_src[(y+1)*_c_w])+64)>>7,255); - } - for(;y<_c_h;y+=2){ - _dst[(y>>1)*_c_w]=OC_CLAMPI(0,(3*(_src[(y-2)*_c_w] - +_src[(_c_h-1)*_c_w])-17*(_src[(y-1)*_c_w] - +_src[OC_MINI(y+2,_c_h-1)*_c_w]) - +78*(_src[y*_c_w]+_src[OC_MINI(y+1,_c_h-1)*_c_w])+64)>>7,255); - } - _src++; - _dst++; - } -} - -/*420jpeg chroma samples are sited like: - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - - 422jpeg chroma samples are sited like: - Y---BR--Y-------Y---BR--Y------- - | | | | - | | | | - | | | | - Y---BR--Y-------Y---BR--Y------- - | | | | - | | | | - | | | | - Y---BR--Y-------Y---BR--Y------- - | | | | - | | | | - | | | | - Y---BR--Y-------Y---BR--Y------- - | | | | - | | | | - | | | | - - We use a resampling filter to decimate the chroma planes by two in the - vertical direction.*/ -static void y4m_convert_422jpeg_420jpeg(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ - int c_w; - int c_h; - int c_sz; - int dst_c_w; - int dst_c_h; - int dst_c_sz; - int pli; - /*Skip past the luma data.*/ - _dst+=_y4m->pic_w*_y4m->pic_h; - /*Compute the size of each chroma plane.*/ - c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; - c_h=_y4m->pic_h; - dst_c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; - dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; - c_sz=c_w*c_h; - dst_c_sz=dst_c_w*dst_c_h; - for(pli=1;pli<3;pli++){ - y4m_422jpeg_420jpeg_helper(_dst,_aux,c_w,c_h); - _aux+=c_sz; - _dst+=dst_c_sz; - } -} - -/*420jpeg chroma samples are sited like: - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - - 422 chroma samples are sited like: - YBR-----Y-------YBR-----Y------- - | | | | - | | | | - | | | | - YBR-----Y-------YBR-----Y------- - | | | | - | | | | - | | | | - YBR-----Y-------YBR-----Y------- - | | | | - | | | | - | | | | - YBR-----Y-------YBR-----Y------- - | | | | - | | | | - | | | | - - We use a resampling filter to shift the original site locations one quarter - pixel (at the original chroma resolution) to the right. - Then we use a second resampling filter to decimate the chroma planes by two - in the vertical direction.*/ -static void y4m_convert_422_420jpeg(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ - unsigned char *tmp; - int c_w; - int c_h; - int c_sz; - int dst_c_h; - int dst_c_sz; - int pli; - /*Skip past the luma data.*/ - _dst+=_y4m->pic_w*_y4m->pic_h; - /*Compute the size of each chroma plane.*/ - c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; - c_h=_y4m->pic_h; - dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; - c_sz=c_w*c_h; - dst_c_sz=c_w*dst_c_h; - tmp=_aux+2*c_sz; - for(pli=1;pli<3;pli++){ - /*In reality, the horizontal and vertical steps could be pipelined, for - less memory consumption and better cache performance, but we do them - separately for simplicity.*/ - /*First do horizontal filtering (convert to 422jpeg)*/ - y4m_42xmpeg2_42xjpeg_helper(tmp,_aux,c_w,c_h); - /*Now do the vertical filtering.*/ - y4m_422jpeg_420jpeg_helper(_dst,tmp,c_w,c_h); - _aux+=c_sz; - _dst+=dst_c_sz; - } -} - -/*420jpeg chroma samples are sited like: - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | BR | | BR | - | | | | - Y-------Y-------Y-------Y------- - | | | | - | | | | - | | | | - - 411 chroma samples are sited like: - YBR-----Y-------Y-------Y------- - | | | | - | | | | - | | | | - YBR-----Y-------Y-------Y------- - | | | | - | | | | - | | | | - YBR-----Y-------Y-------Y------- - | | | | - | | | | - | | | | - YBR-----Y-------Y-------Y------- - | | | | - | | | | - | | | | - - We use a filter to resample at site locations one eighth pixel (at the source - chroma plane's horizontal resolution) and five eighths of a pixel to the - right. - Then we use another filter to decimate the planes by 2 in the vertical - direction.*/ -static void y4m_convert_411_420jpeg(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ - unsigned char *tmp; - int c_w; - int c_h; - int c_sz; - int dst_c_w; - int dst_c_h; - int dst_c_sz; - int tmp_sz; - int pli; - int y; - int x; - /*Skip past the luma data.*/ - _dst+=_y4m->pic_w*_y4m->pic_h; - /*Compute the size of each chroma plane.*/ - c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; - c_h=_y4m->pic_h; - dst_c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; - dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; - c_sz=c_w*c_h; - dst_c_sz=dst_c_w*dst_c_h; - tmp_sz=dst_c_w*c_h; - tmp=_aux+2*c_sz; - for(pli=1;pli<3;pli++){ - /*In reality, the horizontal and vertical steps could be pipelined, for - less memory consumption and better cache performance, but we do them - separately for simplicity.*/ - /*First do horizontal filtering (convert to 422jpeg)*/ - for(y=0;y>7,255); - tmp[x<<1|1]=(unsigned char)OC_CLAMPI(0,(47*_aux[0] - +86*_aux[OC_MINI(1,c_w-1)]-5*_aux[OC_MINI(2,c_w-1)]+64)>>7,255); - } - for(;x>7,255); - tmp[x<<1|1]=(unsigned char)OC_CLAMPI(0,(-3*_aux[x-1]+50*_aux[x] - +86*_aux[x+1]-5*_aux[x+2]+64)>>7,255); - } - for(;x>7,255); - if((x<<1|1)>7,255); - } - } - tmp+=dst_c_w; - _aux+=c_w; - } - tmp-=tmp_sz; - /*Now do the vertical filtering.*/ - y4m_422jpeg_420jpeg_helper(_dst,tmp,dst_c_w,c_h); - _dst+=dst_c_sz; - } -} - -/*Convert 444 to 420jpeg.*/ -static void y4m_convert_444_420jpeg(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ - unsigned char *tmp; - int c_w; - int c_h; - int c_sz; - int dst_c_w; - int dst_c_h; - int dst_c_sz; - int tmp_sz; - int pli; - int y; - int x; - /*Skip past the luma data.*/ - _dst+=_y4m->pic_w*_y4m->pic_h; - /*Compute the size of each chroma plane.*/ - c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h; - c_h=_y4m->pic_h; - dst_c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; - dst_c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; - c_sz=c_w*c_h; - dst_c_sz=dst_c_w*dst_c_h; - tmp_sz=dst_c_w*c_h; - tmp=_aux+2*c_sz; - for(pli=1;pli<3;pli++){ - /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/ - for(y=0;y>1]=OC_CLAMPI(0,(64*_aux[0]+78*_aux[OC_MINI(1,c_w-1)] - -17*_aux[OC_MINI(2,c_w-1)] - +3*_aux[OC_MINI(3,c_w-1)]+64)>>7,255); - } - for(;x>1]=OC_CLAMPI(0,(3*(_aux[x-2]+_aux[x+3]) - -17*(_aux[x-1]+_aux[x+2])+78*(_aux[x]+_aux[x+1])+64)>>7,255); - } - for(;x>1]=OC_CLAMPI(0,(3*(_aux[x-2]+_aux[c_w-1])- - 17*(_aux[x-1]+_aux[OC_MINI(x+2,c_w-1)])+ - 78*(_aux[x]+_aux[OC_MINI(x+1,c_w-1)])+64)>>7,255); - } - tmp+=dst_c_w; - _aux+=c_w; - } - tmp-=tmp_sz; - /*Now do the vertical filtering.*/ - y4m_422jpeg_420jpeg_helper(_dst,tmp,dst_c_w,c_h); - _dst+=dst_c_sz; - } -} - -/*The image is padded with empty chroma components at 4:2:0.*/ -static void y4m_convert_mono_420jpeg(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ - int c_sz; - _dst+=_y4m->pic_w*_y4m->pic_h; - c_sz=((_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h)* - ((_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v); - memset(_dst,128,c_sz*2); -} - -/*No conversion function needed.*/ -static void y4m_convert_null(y4m_input *_y4m,unsigned char *_dst, - unsigned char *_aux){ -} - -int y4m_input_open(y4m_input *_y4m,FILE *_fin,char *_skip,int _nskip){ - char buffer[80]; - int ret; - int i; - /*Read until newline, or 80 cols, whichever happens first.*/ - for(i=0;i<79;i++){ - if(_nskip>0){ - buffer[i]=*_skip++; - _nskip--; - } - else{ - ret=fread(buffer+i,1,1,_fin); - if(ret<1)return -1; - } - if(buffer[i]=='\n')break; - } - /*We skipped too much header data.*/ - if(_nskip>0)return -1; - if(i==79){ - fprintf(stderr,"Error parsing header; not a YUV2MPEG2 file?\n"); - return -1; - } - buffer[i]='\0'; - if(memcmp(buffer,"YUV4MPEG",8)){ - fprintf(stderr,"Incomplete magic for YUV4MPEG file.\n"); - return -1; - } - if(buffer[8]!='2'){ - fprintf(stderr,"Incorrect YUV input file version; YUV4MPEG2 required.\n"); - } - ret=y4m_parse_tags(_y4m,buffer+5); - if(ret<0){ - fprintf(stderr,"Error parsing YUV4MPEG2 header.\n"); - return ret; - } - if(_y4m->interlace=='?'){ - fprintf(stderr,"Warning: Input video interlacing format unknown; " - "assuming progressive scan.\n"); - } - else if(_y4m->interlace!='p'){ - fprintf(stderr,"Input video is interlaced; " - "Only progressive scan handled.\n"); - return -1; - } - if(strcmp(_y4m->chroma_type,"420")==0|| - strcmp(_y4m->chroma_type,"420jpeg")==0){ - _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h - +2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); - /*Natively supported: no conversion required.*/ - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=0; - _y4m->convert=y4m_convert_null; - } - else if(strcmp(_y4m->chroma_type,"420mpeg2")==0){ - _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*Chroma filter required: read into the aux buf first.*/ - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz= - 2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); - _y4m->convert=y4m_convert_42xmpeg2_42xjpeg; - } - else if(strcmp(_y4m->chroma_type,"420paldv")==0){ - _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*Chroma filter required: read into the aux buf first. - We need to make two filter passes, so we need some extra space in the - aux buffer.*/ - _y4m->aux_buf_sz=3*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); - _y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2); - _y4m->convert=y4m_convert_42xpaldv_42xjpeg; - } - else if(strcmp(_y4m->chroma_type,"422jpeg")==0){ - _y4m->src_c_dec_h=_y4m->dst_c_dec_h=2; - _y4m->src_c_dec_v=1; - _y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*Chroma filter required: read into the aux buf first.*/ - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*_y4m->pic_h; - _y4m->convert=y4m_convert_422jpeg_420jpeg; - } - else if(strcmp(_y4m->chroma_type,"422")==0){ - _y4m->src_c_dec_h=_y4m->dst_c_dec_h=2; - _y4m->src_c_dec_v=1; - _y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*Chroma filter required: read into the aux buf first. - We need to make two filter passes, so we need some extra space in the - aux buffer.*/ - _y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*_y4m->pic_h; - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz+((_y4m->pic_w+1)/2)*_y4m->pic_h; - _y4m->convert=y4m_convert_422_420jpeg; - } - else if(strcmp(_y4m->chroma_type,"411")==0){ - _y4m->src_c_dec_h=4; - _y4m->dst_c_dec_h=2; - _y4m->src_c_dec_v=1; - _y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*Chroma filter required: read into the aux buf first. - We need to make two filter passes, so we need some extra space in the - aux buffer.*/ - _y4m->aux_buf_read_sz=2*((_y4m->pic_w+3)/4)*_y4m->pic_h; - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz+((_y4m->pic_w+1)/2)*_y4m->pic_h; - _y4m->convert=y4m_convert_411_420jpeg; - } - else if(strcmp(_y4m->chroma_type,"444")==0){ - _y4m->src_c_dec_h=1; - _y4m->dst_c_dec_h=2; - _y4m->src_c_dec_v=1; - _y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*Chroma filter required: read into the aux buf first. - We need to make two filter passes, so we need some extra space in the - aux buffer.*/ - _y4m->aux_buf_read_sz=2*_y4m->pic_w*_y4m->pic_h; - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz+((_y4m->pic_w+1)/2)*_y4m->pic_h; - _y4m->convert=y4m_convert_444_420jpeg; - } - else if(strcmp(_y4m->chroma_type,"444alpha")==0){ - _y4m->src_c_dec_h=1; - _y4m->dst_c_dec_h=2; - _y4m->src_c_dec_v=1; - _y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*Chroma filter required: read into the aux buf first. - We need to make two filter passes, so we need some extra space in the - aux buffer. - The extra plane also gets read into the aux buf. - It will be discarded.*/ - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=3*_y4m->pic_w*_y4m->pic_h; - _y4m->convert=y4m_convert_444_420jpeg; - } - else if(strcmp(_y4m->chroma_type,"mono")==0){ - _y4m->src_c_dec_h=_y4m->src_c_dec_v=0; - _y4m->dst_c_dec_h=_y4m->dst_c_dec_v=2; - _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h; - /*No extra space required, but we need to clear the chroma planes.*/ - _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=0; - _y4m->convert=y4m_convert_mono_420jpeg; - } - else{ - fprintf(stderr,"Unknown chroma sampling type: %s\n",_y4m->chroma_type); - return -1; - } - /*The size of the final frame buffers is always computed from the - destination chroma decimation type.*/ - _y4m->dst_buf_sz=_y4m->pic_w*_y4m->pic_h - +2*((_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h)* - ((_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v); - _y4m->dst_buf=(unsigned char *)malloc(_y4m->dst_buf_sz); - _y4m->aux_buf=(unsigned char *)malloc(_y4m->aux_buf_sz); - return 0; -} - -void y4m_input_close(y4m_input *_y4m){ - free(_y4m->dst_buf); - free(_y4m->aux_buf); -} - -int y4m_input_fetch_frame(y4m_input *_y4m,FILE *_fin,vpx_image_t *_img){ - char frame[6]; - int pic_sz; - int c_w; - int c_h; - int c_sz; - int ret; - /*Read and skip the frame header.*/ - ret=fread(frame,1,6,_fin); - if(ret<6)return 0; - if(memcmp(frame,"FRAME",5)){ - fprintf(stderr,"Loss of framing in Y4M input data\n"); - return -1; - } - if(frame[5]!='\n'){ - char c; - int j; - for(j=0;j<79&&fread(&c,1,1,_fin)&&c!='\n';j++); - if(j==79){ - fprintf(stderr,"Error parsing Y4M frame header\n"); - return -1; - } - } - /*Read the frame data that needs no conversion.*/ - if(fread(_y4m->dst_buf,1,_y4m->dst_buf_read_sz,_fin)!=_y4m->dst_buf_read_sz){ - fprintf(stderr,"Error reading Y4M frame data.\n"); - return -1; - } - /*Read the frame data that does need conversion.*/ - if(fread(_y4m->aux_buf,1,_y4m->aux_buf_read_sz,_fin)!=_y4m->aux_buf_read_sz){ - fprintf(stderr,"Error reading Y4M frame data.\n"); - return -1; - } - /*Now convert the just read frame.*/ - (*_y4m->convert)(_y4m,_y4m->dst_buf,_y4m->aux_buf); - /*Fill in the frame buffer pointers. - We don't use vpx_img_wrap() because it forces padding for odd picture - sizes, which would require a separate fread call for every row.*/ - memset(_img,0,sizeof(*_img)); - /*Y4M has the planes in Y'CbCr order, which libvpx calls Y, U, and V.*/ - _img->fmt=IMG_FMT_I420; - _img->w=_img->d_w=_y4m->pic_w; - _img->h=_img->d_h=_y4m->pic_h; - /*This is hard-coded to 4:2:0 for now, as that's all VP8 supports.*/ - _img->x_chroma_shift=1; - _img->y_chroma_shift=1; - _img->bps=12; - /*Set up the buffer pointers.*/ - pic_sz=_y4m->pic_w*_y4m->pic_h; - c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h; - c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v; - c_sz=c_w*c_h; - _img->stride[PLANE_Y]=_y4m->pic_w; - _img->stride[PLANE_U]=_img->stride[PLANE_V]=c_w; - _img->planes[PLANE_Y]=_y4m->dst_buf; - _img->planes[PLANE_U]=_y4m->dst_buf+pic_sz; - _img->planes[PLANE_V]=_y4m->dst_buf+pic_sz+c_sz; - return 1; -} diff --git a/wcap/y4minput.h b/wcap/y4minput.h deleted file mode 100644 index 1a01bcd..0000000 --- a/wcap/y4minput.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2010 The WebM project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - * - * Based on code from the OggTheora software codec source code, - * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors. - */ -#if !defined(_y4minput_H) -# define _y4minput_H (1) -# include -# include "vpx/vpx_image.h" - - - -typedef struct y4m_input y4m_input; - - - -/*The function used to perform chroma conversion.*/ -typedef void (*y4m_convert_func)(y4m_input *_y4m, - unsigned char *_dst,unsigned char *_src); - - - -struct y4m_input{ - int pic_w; - int pic_h; - int fps_n; - int fps_d; - int par_n; - int par_d; - char interlace; - int src_c_dec_h; - int src_c_dec_v; - int dst_c_dec_h; - int dst_c_dec_v; - char chroma_type[16]; - /*The size of each converted frame buffer.*/ - size_t dst_buf_sz; - /*The amount to read directly into the converted frame buffer.*/ - size_t dst_buf_read_sz; - /*The size of the auxilliary buffer.*/ - size_t aux_buf_sz; - /*The amount to read into the auxilliary buffer.*/ - size_t aux_buf_read_sz; - y4m_convert_func convert; - unsigned char *dst_buf; - unsigned char *aux_buf; -}; - -int y4m_input_open(y4m_input *_y4m,FILE *_fin,char *_skip,int _nskip); -void y4m_input_close(y4m_input *_y4m); -int y4m_input_fetch_frame(y4m_input *_y4m,FILE *_fin,vpx_image_t *img); - -#endif