diff options
-rw-r--r-- | wcap/COPYING | 34 | ||||
-rw-r--r-- | wcap/EbmlIDs.h | 231 | ||||
-rw-r--r-- | wcap/EbmlWriter.c | 171 | ||||
-rw-r--r-- | wcap/EbmlWriter.h | 38 | ||||
-rw-r--r-- | wcap/Makefile.am | 26 | ||||
-rw-r--r-- | wcap/README | 46 | ||||
-rw-r--r-- | wcap/args.c | 265 | ||||
-rw-r--r-- | wcap/args.h | 54 | ||||
-rw-r--r-- | wcap/main.c | 240 | ||||
-rw-r--r-- | wcap/mem_ops.h | 234 | ||||
-rw-r--r-- | wcap/mem_ops_aligned.h | 157 | ||||
-rw-r--r-- | wcap/tools_common.c | 30 | ||||
-rw-r--r-- | wcap/tools_common.h | 16 | ||||
-rw-r--r-- | wcap/vpx_config.h | 2 | ||||
-rw-r--r-- | wcap/vpx_timer.h | 120 | ||||
-rw-r--r-- | wcap/vpxenc.c | 2664 | ||||
-rw-r--r-- | wcap/wcap-snapshot.c | 84 | ||||
-rw-r--r-- | wcap/y4minput.c | 871 | ||||
-rw-r--r-- | wcap/y4minput.h | 60 |
19 files changed, 265 insertions, 5078 deletions
diff --git a/wcap/COPYING b/wcap/COPYING deleted file mode 100644 index 3d019b10..00000000 --- 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 3418e365..00000000 --- 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 fbf2c66e..00000000 --- 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 <stdlib.h> -#include <wchar.h> -#include <string.h> -#include <limits.h> -#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 324c9bca..00000000 --- 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 <stddef.h> -#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 187c5c3e..da0ba904 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 dfbddf10..666a7084 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=<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 37ba7788..00000000 --- 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 <stdlib.h> -#include <string.h> -#include <limits.h> -#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 ? " <arg>" : ""; - char *long_val = def->has_val ? "=<arg>" : ""; - - 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 7963fa6b..00000000 --- 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 <stdio.h> - -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 00000000..bdbc8cb7 --- /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 <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <sys/mman.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> + +#include <cairo.h> + +#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=<frame>] [--all] \n" + "\t[--rate=<num:denom>] <wcap file>\n\n" + "\t--help\t\t\tthis help text\n" + "\t--yuv2mpeg4\t\tdump wcap file in yuv4mpeg format\n" + "\t--frame=<frame>\t\twrite out the given frame number as png\n" + "\t--all\t\t\twrite all frames as pngs\n" + "\t--rate=<num:denom>\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 0e523681..00000000 --- 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 0fbba65e..00000000 --- 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 6f950286..00000000 --- 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 <stdio.h> -#include "tools_common.h" -#if defined(_WIN32) || defined(__OS2__) -#include <io.h> -#include <fcntl.h> - -#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 80c97473..00000000 --- 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 b4e8c307..00000000 --- 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 d07e0861..00000000 --- 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 <windows.h> -#else -/* - * POSIX specific includes - */ -#include <sys/time.h> - -/* 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 5e9e34d9..00000000 --- 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 <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <limits.h> -#include <assert.h> -#include "vpx/vpx_encoder.h" -#if USE_POSIX_MMAP -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <fcntl.h> -#include <unistd.h> -#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; i<glob->cues; 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 <options> -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; i<buckets; i++) - { - int len; - int j; - float pct; - - pct = 100.0 * (float)bucket[i].count / (float)total; - len = HIST_BAR_MAX * bucket[i].count / scale; - if(len < 1) - len = 1; - assert(len <= HIST_BAR_MAX); - - if(bucket[i].low == bucket[i].high) - fprintf(stderr, pat1, bucket[i].low, ""); - else - fprintf(stderr, pat2, bucket[i].low, bucket[i].high); - - for(j=0; j<HIST_BAR_MAX; j++) - fprintf(stderr, j<len?"=":" "); - fprintf(stderr, "\t%5d (%6.2f%%)\n",bucket[i].count,pct); - } -} - - -static void show_q_histogram(const int counts[64], int max_buckets) -{ - struct hist_bucket bucket[64]; - int buckets = 0; - int total = 0; - int scale; - int i; - - - for(i=0; i<64; i++) - { - if(counts[i]) - { - bucket[buckets].low = bucket[buckets].high = i; - bucket[buckets].count = counts[i]; - buckets++; - total += counts[i]; - } - } - - fprintf(stderr, "\nQuantizer Selection:\n"); - scale = merge_hist_buckets(bucket, &buckets, max_buckets); - show_histogram(bucket, buckets, total, scale); -} - - -#define RATE_BINS (100) -struct rate_hist -{ - int64_t *pts; - int *sz; - int samples; - int frames; - struct hist_bucket bucket[RATE_BINS]; - int total; -}; - - -static void init_rate_histogram(struct rate_hist *hist, - const vpx_codec_enc_cfg_t *cfg, - const vpx_rational_t *fps) -{ - int i; - - /* Determine the number of samples in the buffer. Use the file's framerate - * to determine the number of frames in rc_buf_sz milliseconds, with an - * adjustment (5/4) to account for alt-refs - */ - hist->samples = 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; i<RATE_BINS; i++) - { - hist->bucket[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; j<config->arg_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 01df7a28..00000000 --- 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 <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <sys/mman.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> - -#include <cairo.h> - -#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 dd51421d..00000000 --- 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 <stdlib.h> -#include <string.h> -#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<OC_MINI(_c_w,2);x++){ - _dst[x]=(unsigned char)OC_CLAMPI(0,(4*_src[0]-17*_src[OC_MAXI(x-1,0)]+ - 114*_src[x]+35*_src[OC_MINI(x+1,_c_w-1)]-9*_src[OC_MINI(x+2,_c_w-1)]+ - _src[OC_MINI(x+3,_c_w-1)]+64)>>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<c_w;x++){ - for(y=0;y<OC_MINI(c_h,3);y++){ - _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,(tmp[0] - -9*tmp[OC_MAXI(y-2,0)*c_w]+35*tmp[OC_MAXI(y-1,0)*c_w] - +114*tmp[y*c_w]-17*tmp[OC_MINI(y+1,c_h-1)*c_w] - +4*tmp[OC_MINI(y+2,c_h-1)*c_w]+64)>>7,255); - } - for(;y<c_h-2;y++){ - _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,(tmp[(y-3)*c_w] - -9*tmp[(y-2)*c_w]+35*tmp[(y-1)*c_w]+114*tmp[y*c_w] - -17*tmp[(y+1)*c_w]+4*tmp[(y+2)*c_w]+64)>>7,255); - } - for(;y<c_h;y++){ - _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,(tmp[(y-3)*c_w] - -9*tmp[(y-2)*c_w]+35*tmp[(y-1)*c_w]+114*tmp[y*c_w] - -17*tmp[OC_MINI(y+1,c_h-1)*c_w]+4*tmp[(c_h-1)*c_w]+64)>>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<c_w;x++){ - for(y=0;y<OC_MINI(c_h,2);y++){ - _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,(4*tmp[0] - -17*tmp[OC_MAXI(y-1,0)*c_w]+114*tmp[y*c_w] - +35*tmp[OC_MINI(y+1,c_h-1)*c_w]-9*tmp[OC_MINI(y+2,c_h-1)*c_w] - +tmp[OC_MINI(y+3,c_h-1)*c_w]+64)>>7,255); - } - for(;y<c_h-3;y++){ - _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,(4*tmp[(y-2)*c_w] - -17*tmp[(y-1)*c_w]+114*tmp[y*c_w]+35*tmp[(y+1)*c_w] - -9*tmp[(y+2)*c_w]+tmp[(y+3)*c_w]+64)>>7,255); - } - for(;y<c_h;y++){ - _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,(4*tmp[(y-2)*c_w] - -17*tmp[(y-1)*c_w]+114*tmp[y*c_w]+35*tmp[OC_MINI(y+1,c_h-1)*c_w] - -9*tmp[OC_MINI(y+2,c_h-1)*c_w]+tmp[(c_h-1)*c_w]+64)>>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<OC_MINI(_c_h,2);y+=2){ - _dst[(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<c_h;y++){ - /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a - 4-tap Mitchell window.*/ - for(x=0;x<OC_MINI(c_w,1);x++){ - tmp[x<<1]=(unsigned char)OC_CLAMPI(0,(111*_aux[0] - +18*_aux[OC_MINI(1,c_w-1)]-_aux[OC_MINI(2,c_w-1)]+64)>>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<c_w-2;x++){ - tmp[x<<1]=(unsigned char)OC_CLAMPI(0,(_aux[x-1]+110*_aux[x] - +18*_aux[x+1]-_aux[x+2]+64)>>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<c_w;x++){ - tmp[x<<1]=(unsigned char)OC_CLAMPI(0,(_aux[x-1]+110*_aux[x] - +18*_aux[OC_MINI(x+1,c_w-1)]-_aux[c_w-1]+64)>>7,255); - if((x<<1|1)<dst_c_w){ - tmp[x<<1|1]=(unsigned char)OC_CLAMPI(0,(-3*_aux[x-1]+50*_aux[x] - +86*_aux[OC_MINI(x+1,c_w-1)]-5*_aux[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; - } -} - -/*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<c_h;y++){ - for(x=0;x<OC_MINI(c_w,2);x+=2){ - tmp[x>>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<c_w-3;x+=2){ - tmp[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<c_w;x+=2){ - tmp[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 1a01bcda..00000000 --- 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 <stdio.h> -# 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 |