parent
5fb70bf301
commit
89060c0a8b
@ -1,3 +1,3 @@ |
|||||||
SUBDIRS = shared src clients data protocol tests
|
SUBDIRS = shared src clients wcap-decode data protocol tests
|
||||||
|
|
||||||
DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install
|
DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install
|
||||||
|
@ -0,0 +1,231 @@ |
|||||||
|
// 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 |
@ -0,0 +1,171 @@ |
|||||||
|
// 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
|
@ -0,0 +1,38 @@ |
|||||||
|
#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 |
@ -0,0 +1,265 @@ |
|||||||
|
/*
|
||||||
|
* 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); |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
/*
|
||||||
|
* 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 |
@ -0,0 +1,234 @@ |
|||||||
|
/*
|
||||||
|
* 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; |
||||||
|
} |
@ -0,0 +1,157 @@ |
|||||||
|
/*
|
||||||
|
* 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 |
@ -0,0 +1,30 @@ |
|||||||
|
/*
|
||||||
|
* 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; |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
/*
|
||||||
|
* 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 |
@ -0,0 +1,120 @@ |
|||||||
|
/*
|
||||||
|
* 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 |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,218 @@ |
|||||||
|
/*
|
||||||
|
* 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> |
||||||
|
|
||||||
|
struct wcap_header { |
||||||
|
uint32_t width, height; |
||||||
|
}; |
||||||
|
|
||||||
|
struct wcap_frame_header { |
||||||
|
uint32_t msecs; |
||||||
|
uint32_t nrects; |
||||||
|
}; |
||||||
|
|
||||||
|
struct wcap_rectangle { |
||||||
|
int32_t x1, y1, x2, y2; |
||||||
|
}; |
||||||
|
|
||||||
|
struct wcap_decoder { |
||||||
|
int fd; |
||||||
|
size_t size; |
||||||
|
void *map, *p, *end; |
||||||
|
uint32_t *frame; |
||||||
|
int width, height; |
||||||
|
}; |
||||||
|
|
||||||
|
static void |
||||||
|
wcap_decoder_decode_rectangle(struct wcap_decoder *decoder, |
||||||
|
struct wcap_rectangle *rect) |
||||||
|
{ |
||||||
|
uint32_t v, *p = decoder->p, *d; |
||||||
|
int width = rect->x2 - rect->x1, height = rect->y2 - rect->y1; |
||||||
|
int x, i, j, k, l, count = width * height; |
||||||
|
|
||||||
|
d = decoder->frame + (rect->y2 - 1) * decoder->width; |
||||||
|
x = rect->x1; |
||||||
|
i = 0; |
||||||
|
while (i < count) { |
||||||
|
v = *p++; |
||||||
|
l = v >> 24; |
||||||
|
if (l < 0xe0) { |
||||||
|
j = l + 1; |
||||||
|
} else { |
||||||
|
j = 1 << (l - 0xe0 + 7); |
||||||
|
} |
||||||
|
|
||||||
|
for (k = 0; k < j; k++) { |
||||||
|
d[x] = (d[x] + v) | 0xff000000; |
||||||
|
x++; |
||||||
|
if (x == rect->x2) { |
||||||
|
x = rect->x1; |
||||||
|
d -= decoder->width; |
||||||
|
} |
||||||
|
} |
||||||
|
i += j; |
||||||
|
} |
||||||
|
|
||||||
|
if (i != count) |
||||||
|
printf("rle encoding longer than expected (%d expected %d)\n", |
||||||
|
i, count); |
||||||
|
|
||||||
|
decoder->p = p; |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
wcap_decoder_get_frame(struct wcap_decoder *decoder) |
||||||
|
{ |
||||||
|
struct wcap_rectangle *rects; |
||||||
|
struct wcap_frame_header *header; |
||||||
|
uint32_t *s; |
||||||
|
uint32_t i; |
||||||
|
int width, height; |
||||||
|
|
||||||
|
if (decoder->p == decoder->end) |
||||||
|
return 0; |
||||||
|
|
||||||
|
header = decoder->p; |
||||||
|
|
||||||
|
rects = (void *) (header + 1); |
||||||
|
decoder->p = (uint32_t *) (rects + header->nrects); |
||||||
|
for (i = 0; i < header->nrects; i++) { |
||||||
|
width = rects[i].x2 - rects[i].x1; |
||||||
|
height = rects[i].y2 - rects[i].y1; |
||||||
|
wcap_decoder_decode_rectangle(decoder, &rects[i]); |
||||||
|
} |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
struct wcap_decoder * |
||||||
|
wcap_decoder_create(const char *filename) |
||||||
|
{ |
||||||
|
struct wcap_decoder *decoder; |
||||||
|
struct wcap_header *header; |
||||||
|
int frame_size; |
||||||
|
struct stat buf; |
||||||
|
|
||||||
|
decoder = malloc(sizeof *decoder); |
||||||
|
if (decoder == NULL) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
decoder->fd = open(filename, O_RDONLY); |
||||||
|
if (decoder->fd == -1) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
fstat(decoder->fd, &buf); |
||||||
|
decoder->size = buf.st_size; |
||||||
|
decoder->map = mmap(NULL, decoder->size, |
||||||
|
PROT_READ, MAP_PRIVATE, decoder->fd, 0); |
||||||
|
|
||||||
|
header = decoder->map; |
||||||
|
decoder->width = header->width; |
||||||
|
decoder->height = header->height; |
||||||
|
decoder->p = header + 1; |
||||||
|
decoder->end = decoder->map + decoder->size; |
||||||
|
|
||||||
|
frame_size = header->width * header->height * 4; |
||||||
|
decoder->frame = malloc(frame_size); |
||||||
|
memset(decoder->frame, 0, frame_size); |
||||||
|
|
||||||
|
return decoder; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
wcap_decoder_destroy(struct wcap_decoder *decoder) |
||||||
|
{ |
||||||
|
munmap(decoder->map, decoder->size); |
||||||
|
free(decoder->frame); |
||||||
|
free(decoder); |
||||||
|
} |
||||||
|
|
||||||
|
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 void |
||||||
|
write_all_pngs(struct wcap_decoder *decoder, int frame) |
||||||
|
{ |
||||||
|
char filename[200]; |
||||||
|
int i; |
||||||
|
|
||||||
|
i = 0; |
||||||
|
while (wcap_decoder_get_frame(decoder)) { |
||||||
|
if (i == frame || frame == -1) { |
||||||
|
snprintf(filename, sizeof filename, |
||||||
|
"wcap-frame-%d.png", i); |
||||||
|
write_png(decoder, filename); |
||||||
|
printf("wrote %s\n", filename); |
||||||
|
} |
||||||
|
i++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
struct wcap_decoder *decoder; |
||||||
|
int i, output_frame; |
||||||
|
|
||||||
|
if (argc != 2 && argc != 3) { |
||||||
|
fprintf(stderr, "usage: wcap-decode 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); |
||||||
|
|
||||||
|
if (0) |
||||||
|
write_all_pngs(decoder, -1); |
||||||
|
else |
||||||
|
write_webm(decoder); |
||||||
|
|
||||||
|
printf("wcap file: size %dx%d, %d frames\n", |
||||||
|
decoder->width, decoder->height, i); |
||||||
|
|
||||||
|
wcap_decoder_destroy(decoder); |
||||||
|
} |
@ -0,0 +1,871 @@ |
|||||||
|
/*
|
||||||
|
* 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; |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/*
|
||||||
|
* 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 |
Loading…
Reference in new issue