include asf_reader in compilation may break GCC4 builds

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30498 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2009-04-30 10:23:13 +00:00
parent 94793d4d86
commit 22245b2dce
27 changed files with 1081 additions and 566 deletions
+2
View File
@@ -22,6 +22,8 @@ SubInclude HAIKU_TOP src add-ons media plugins speex ;
SubInclude HAIKU_TOP src add-ons media plugins mov_reader ;
SubInclude HAIKU_TOP src add-ons media plugins mp4_reader ;
SubInclude HAIKU_TOP src add-ons media plugins asf_reader ;
# The following add-ons are GPL licensed, and can only be used with
# software whose license is GPL compatible. To include these GPL
# licensed add-ons, you need to run configure with the --include-gpl-addons
+3 -1
View File
@@ -8,12 +8,14 @@ SubDirHdrs [ FDirName $(SUBDIR) libavcodec ] ;
SubDirHdrs [ FDirName $(SUBDIR) libavutil ] ;
SubDirHdrs [ FDirName $(SUBDIR) libswscale ] ;
SubDirCcFlags -fomit-frame-pointer -DPIC -fno-common ;
Addon avcodec :
avcodec.cpp
codectbl.cpp
gfx_conv_c.cpp
gfx_conv_c_lookup.cpp
# gfx_conv_mmx.cpp
gfx_conv_mmx.cpp
gfx_util.cpp
:
libavcodec.a
@@ -466,12 +466,18 @@ avCodec::Decode(void *out_buffer, int64 *out_frameCount,
if (fChunkBufferSize == 0) {
media_header chunk_mh;
status_t err;
printf("Asking for more data after %Ld frames\n",fFrame);
err = GetNextChunk(&fChunkBuffer, &fChunkBufferSize, &chunk_mh);
if (err == B_LAST_BUFFER_ERROR) {
printf("Last Chunk with chunk size %ld\n",fChunkBufferSize);
return err;
}
if (err != B_OK || fChunkBufferSize < 0) {
TRACE("GetNextChunk error %ld\n",fChunkBufferSize);
printf("GetNextChunk error %ld\n",fChunkBufferSize);
fChunkBufferSize = 0;
break;
}
printf("Got a Chunk with start time of %Ld\n",chunk_mh.start_time);
fChunkBufferOffset = 0;
fStartTime = chunk_mh.start_time;
if (*out_frameCount == 0)
@@ -69,6 +69,7 @@ const struct codec_table gCodecTable[] = {
{CODEC_ID_WMAV1, B_MEDIA_ENCODED_AUDIO, B_WAV_FORMAT_FAMILY, 0x160, "MS WMA v1"},
{CODEC_ID_WMAV2, B_MEDIA_ENCODED_AUDIO, B_WAV_FORMAT_FAMILY, 0x161, "MS WMA v2"},
{CODEC_ID_VOXWARE, B_MEDIA_ENCODED_AUDIO, B_WAV_FORMAT_FAMILY, 0x75, "Voxware"},
{CODEC_ID_CINEPAK, B_MEDIA_ENCODED_VIDEO, B_AVI_FORMAT_FAMILY, FOURCC('cvid'), "Cinepak Video"},
{CODEC_ID_CINEPAK, B_MEDIA_ENCODED_VIDEO, B_QUICKTIME_FORMAT_FAMILY, 'cvid', "Cinepak Video"},
@@ -0,0 +1,38 @@
extern "C" {
#include "libavcodec/imgconvert.h"
}
void gfx_conv_null_mmx(AVFrame *in, AVFrame *out, int width, int height) {
memcpy(out->data[0], in->data[0], height * in->linesize[0]);
}
void gfx_conv_yuv410p_ycbcr422_mmx(AVFrame *in, AVFrame *out, int width, int height)
{
img_convert((AVPicture *)out,PIX_FMT_YUV422P,(const AVPicture *)in,PIX_FMT_YUV410P,width,height);
}
void gfx_conv_yuv411p_ycbcr422_mmx(AVFrame *in, AVFrame *out, int width, int height)
{
img_convert((AVPicture *)out,PIX_FMT_YUV422P,(const AVPicture *)in,PIX_FMT_YUV411P,width,height);
}
void gfx_conv_yuv420p_ycbcr422_mmx(AVFrame *in, AVFrame *out, int width, int height)
{
img_convert((AVPicture *)out,PIX_FMT_YUV422P,(const AVPicture *)in,PIX_FMT_YUV420P,width,height);
}
void gfx_conv_yuv410p_rgb32_mmx(AVFrame *in, AVFrame *out, int width, int height)
{
img_convert((AVPicture *)out,PIX_FMT_RGB32,(const AVPicture *)in,PIX_FMT_YUV410P,width,height);
}
void gfx_conv_yuv411p_rgb32_mmx(AVFrame *in, AVFrame *out, int width, int height)
{
img_convert((AVPicture *)out,PIX_FMT_RGB32,(const AVPicture *)in,PIX_FMT_YUV411P,width,height);
}
void gfx_conv_yuv420p_rgb32_mmx(AVFrame *in, AVFrame *out, int width, int height)
{
img_convert((AVPicture *)out,PIX_FMT_RGB32,(const AVPicture *)in,PIX_FMT_YUV420P,width,height);
}
@@ -5,8 +5,6 @@
#include <GraphicsDefs.h>
#include "libavcodec/avcodec.h"
bool IsMmxCpu();
void gfx_conv_null_mmx(AVFrame *in, AVFrame *out, int width, int height);
void gfx_conv_yuv410p_ycbcr422_mmx(AVFrame *in, AVFrame *out, int width, int height);
@@ -16,14 +16,14 @@
#endif
//#define INCLUDE_MMX defined(__INTEL__)
#define INCLUDE_MMX 0
#define INCLUDE_MMX 1
// this function will try to find the best colorspaces for both the ff-codec and
// the Media Kit sides.
gfx_convert_func resolve_colorspace(color_space colorSpace, PixelFormat pixelFormat)
{
#if INCLUDE_MMX
bool mmx = IsMmxCpu();
bool mmx = true;
#endif
switch (colorSpace)
@@ -14,7 +14,7 @@ TARGET_WARNING_CCFLAGS = [ FFilter $(TARGET_WARNING_CCFLAGS)
if $(HAIKU_GCC_VERSION[1]) >= 3 {
SubDirCcFlags -fomit-frame-pointer -fno-pic ;
} else {
SubDirCcFlags -fomit-frame-pointer -DPIC ;
SubDirCcFlags -fomit-frame-pointer -DPIC -fno-common ;
}
local defines ;
@@ -54,7 +54,9 @@
#define HAVE_DLFCN_H 0
#define HAVE_DLOPEN 0
#define HAVE_DOS_PATHS 0
#define HAVE_EBP_AVAILABLE 0
// Jamfile must have -fomit_frame_pointer
#define HAVE_EBP_AVAILABLE 1
// We use position independant code so no EBX
#define HAVE_EBX_AVAILABLE 0
#define HAVE_FAST_64BIT 0
#define HAVE_FAST_CMOV 0
@@ -75,10 +77,10 @@
#define HAVE_MACHINE_IOCTL_BT848_H 0
#define HAVE_MACHINE_IOCTL_METEOR_H 0
#define HAVE_MALLOC_H 1
#define HAVE_MEMALIGN 1
#define HAVE_MEMALIGN 0
#define HAVE_MKSTEMP 1
#define HAVE_PLD 0
#define HAVE_POSIX_MEMALIGN 0
#define HAVE_POSIX_MEMALIGN 1
#define HAVE_PPC64 0
#define HAVE_ROUND 1
#define HAVE_ROUNDF 1
@@ -2412,6 +2412,8 @@ b= t;
}
}
}
#include <stdio.h>
#undef printf
static av_always_inline void hl_decode_mb_internal(H264Context *h, int simple){
MpegEncContext * const s = &h->s;
@@ -2420,6 +2422,8 @@ static av_always_inline void hl_decode_mb_internal(H264Context *h, int simple){
const int mb_xy= h->mb_xy;
const int mb_type= s->current_picture.mb_type[mb_xy];
uint8_t *dest_y, *dest_cb, *dest_cr;
uintptr_t v;
size_t align;
int linesize, uvlinesize /*dct_offset*/;
int i;
int *block_offset = &h->block_offset[0];
@@ -2433,6 +2437,14 @@ static av_always_inline void hl_decode_mb_internal(H264Context *h, int simple){
dest_cb = s->current_picture.data[1] + (mb_x + mb_y * s->uvlinesize) * 8;
dest_cr = s->current_picture.data[2] + (mb_x + mb_y * s->uvlinesize) * 8;
v = (uintptr_t)dest_y;
align = ffs((int)v);
printf("aligned(16): %s: address: %p alignment: %d (2^%u)\n",
align > 4 ? "PASS" : "FAIL", v, 1<<(align-1), align-1);
s->dsp.prefetch(dest_y + (s->mb_x&3)*4*s->linesize + 64, s->linesize, 4);
s->dsp.prefetch(dest_cb + (s->mb_x&7)*s->uvlinesize + 64, dest_cr - dest_cb, 2);
@@ -19,7 +19,7 @@ local defines ;
defines = HAVE_AV_CONFIG_H=1 ;
defines += ARCH_X86=1 ARCH_X86_32=1 ARCH_PPC=0 ARCH_SPARC=0 ;
defines += HAVE_AMD3DNOW=0 HAVE_AMD3DNOWEXT=0 ;
defines += HAVE_MMX=1 HAVE_MMX2=1 HAVE_SSE=0 HAVE_SSE3=1 ;
defines += HAVE_MMX=1 HAVE_MMX2=1 HAVE_SSE=1 HAVE_SSE3=1 ;
defines += HAVE_ALTIVEC=0 ;
defines += HAVE_VIS=0 ;
@@ -2391,6 +2391,56 @@ void ff_x264_deblock_h_luma_intra_sse2(uint8_t *pix, int stride, int alpha, int
#define ff_float_to_int16_interleave6_3dnow(a,b,c) float_to_int16_interleave_misc_3dnow(a,b,c,6)
#define ff_float_to_int16_interleave6_3dn2(a,b,c) float_to_int16_interleave_misc_3dnow(a,b,c,6)
#endif
#include <stdio.h>
#undef printf
void haiku_x264_deblock_v_luma_sse2(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) {
uintptr_t v = (uintptr_t)pix;
size_t align1;
size_t align2;
align1 = ffs((int)v);
printf("V pix aligned(16): %s: address: %p alignment: %d (2^%u)\n",
align1 > 4 ? "PASS" : "FAIL", v, 1<<(align1-1), align1-1);
v = (uintptr_t)tc0;
align2 = ffs((int)v);
printf("V tc0 aligned(16): %s: address: %p alignment: %d (2^%u)\n",
align2 > 4 ? "PASS" : "FAIL", v, 1<<(align2-1), align2-1);
if (align1 > 4 && align2 > 4) {
ff_x264_deblock_v_luma_sse2(pix, stride, alpha, beta, tc0);
} else {
h264_v_loop_filter_luma_mmx2(pix, stride, alpha, beta, tc0);
}
}
void haiku_x264_deblock_h_luma_sse2(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) {
uintptr_t v = (uintptr_t)pix;
size_t align1;
size_t align2;
align1 = ffs((int)v);
printf("H pix aligned(16): %s: address: %p alignment: %d (2^%u)\n",
align1 > 4 ? "PASS" : "FAIL", v, 1<<(align1-1), align1-1);
v = (uintptr_t)tc0;
align2 = ffs((int)v);
printf("H tc0 aligned(16): %s: address: %p alignment: %d (2^%u)\n",
align2 > 4 ? "PASS" : "FAIL", v, 1<<(align2-1), align2-1);
if (align1 > 4 && align2 > 4) {
ff_x264_deblock_h_luma_sse2(pix, stride, alpha, beta, tc0);
} else {
h264_h_loop_filter_luma_mmx2(pix, stride, alpha, beta, tc0);
}
}
#define ff_float_to_int16_interleave6_sse2 ff_float_to_int16_interleave6_sse
#define FLOAT_TO_INT16_INTERLEAVE(cpu, body) \
@@ -2945,8 +2995,8 @@ void dsputil_init_mmx(DSPContext* c, AVCodecContext *avctx)
#endif
if( mm_flags&FF_MM_SSE2 ){
#if ARCH_X86_64 || !defined(__ICC) || __ICC > 1100
c->h264_v_loop_filter_luma = ff_x264_deblock_v_luma_sse2;
c->h264_h_loop_filter_luma = ff_x264_deblock_h_luma_sse2;
c->h264_v_loop_filter_luma = haiku_x264_deblock_v_luma_sse2;
c->h264_h_loop_filter_luma = haiku_x264_deblock_h_luma_sse2;
c->h264_v_loop_filter_luma_intra = ff_x264_deblock_v_luma_intra_sse2;
c->h264_h_loop_filter_luma_intra = ff_x264_deblock_h_luma_intra_sse2;
#endif
@@ -7,7 +7,7 @@ TARGET_WARNING_CCFLAGS = [ FFilter $(TARGET_WARNING_CCFLAGS)
SubDirHdrs [ FDirName $(SUBDIR) .. ] ;
SubDirHdrs [ FDirName $(SUBDIR) ../libavcodec ] ;
SubDirCcFlags -fomit-frame-pointer -DPIC ;
SubDirCcFlags -fomit-frame-pointer -DPIC -fno-common ;
#SubDirCcFlags -DHAVE_AV_CONFIG_H=1 ;
StaticLibrary libavutil.a :
@@ -8,7 +8,7 @@ SubDirHdrs [ FDirName $(SUBDIR) ../libavcodec ] ;
TARGET_WARNING_CCFLAGS = [ FFilter $(TARGET_WARNING_CCFLAGS)
: -Wall -Wmissing-prototypes -Wsign-compare -Wpointer-arith ] ;
SubDirCcFlags -fomit-frame-pointer -DPIC ;
SubDirCcFlags -fomit-frame-pointer -DPIC -fno-common ;
local arch_sources ;
arch_sources = ;
@@ -41,6 +41,17 @@ AtomBase::~AtomBase()
parentAtom = NULL;
}
char *AtomBase::getAtomTypeAsFourcc()
{
fourcc[0] = (char)((atomType >> 24) & 0xff);
fourcc[1] = (char)((atomType >> 16) & 0xff);
fourcc[2] = (char)((atomType >> 8) & 0xff);
fourcc[3] = (char)((atomType >> 0) & 0xff);
fourcc[4] = '\0';
return fourcc;
}
char *AtomBase::getAtomName()
{
char *_result;
@@ -107,7 +118,7 @@ void AtomBase::DisplayAtoms()
void AtomBase::DisplayAtoms(uint32 pindent)
{
Indent(pindent);
printf("%s\n",getAtomName());
printf("(%s)\n",getAtomName());
}
void AtomBase::Indent(uint32 pindent)
@@ -124,10 +135,6 @@ bool AtomBase::IsKnown()
void AtomBase::ReadArrayHeader(array_header *pHeader)
{
Read(&pHeader->Version);
Read(&pHeader->Flags1);
Read(&pHeader->Flags2);
Read(&pHeader->Flags3);
Read(&pHeader->NoEntries);
}
@@ -164,6 +171,17 @@ void AtomBase::Read(uint32 *value)
*value = B_BENDIAN_TO_HOST_INT32(*value);
}
void AtomBase::Read(int32 *value)
{
uint32 bytes_read;
bytes_read = getStream()->Read(value,sizeof(int32));
// Assert((bytes_read == sizeof(int32),"Read Error");
*value = B_BENDIAN_TO_HOST_INT32(*value);
}
void AtomBase::Read(uint16 *value)
{
uint32 bytes_read;
@@ -202,6 +220,52 @@ void AtomBase::Read(uint8 *value, uint32 maxread)
// Assert((bytes_read == maxread,"Read Error");
}
uint64 AtomBase::GetBits(uint64 buffer, uint8 startBit, uint8 totalBits)
{
// startBit should range from 0-63, totalBits should range from 1-64
if ((startBit < 64) && (totalBits > 0) && (totalBits <= 64) && (startBit + totalBits <= 64)) {
// Ok pull from the buffer the bits wanted.
buffer = buffer << startBit;
buffer = buffer >> (64 - (totalBits + startBit) + startBit);
printf("buffer = %Ld\n",buffer);
return buffer;
}
return 0L;
}
uint32 AtomBase::GetBits(uint32 buffer, uint8 startBit, uint8 totalBits)
{
// startBit should range from 0-31, totalBits should range from 1-32
if ((startBit < 32) && (totalBits > 0) && (totalBits <= 32) && (startBit + totalBits <= 32)) {
// Ok pull from the buffer the bits wanted.
buffer = buffer << startBit;
buffer = buffer >> (32 - (startBit + totalBits) + startBit);
return buffer;
}
return 0;
}
FullAtom::FullAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
{
}
FullAtom::~FullAtom()
{
}
void FullAtom::OnProcessMetaData()
{
Read(&Version);
Read(&Flags1);
Read(&Flags2);
Read(&Flags3);
}
AtomContainer::AtomContainer(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
{
TotalChildren = 0;
@@ -214,7 +278,7 @@ AtomContainer::~AtomContainer()
void AtomContainer::DisplayAtoms(uint32 pindent)
{
Indent(pindent);
printf("%ld:%s\n",TotalChildren,getAtomName());
printf("%ld:(%s)\n",TotalChildren,getAtomName());
pindent++;
// for each child
for (uint32 i = 0;i < TotalChildren;i++) {
@@ -101,17 +101,18 @@ public:
uint64 getAtomSize() {return atomSize;};
uint32 getAtomType() {return atomType;};
off_t getAtomOffset() {return atomOffset;};
off_t getStreamOffset() {return streamOffset;};
char *getAtomTypeAsFourcc();
off_t getAtomOffset() { return atomOffset; };
off_t getStreamOffset() { return streamOffset; };
uint64 getDataSize() { return atomSize - 8;};
uint64 getDataSize() {return atomSize - 8;};
uint64 getBytesRemaining();
bool IsType(uint32 patomType) {return patomType == atomType;};
bool IsType(uint32 patomType) { return patomType == atomType; };
void setAtomOffset(off_t patomOffset) {atomOffset = patomOffset;};
void setStreamOffset(off_t pstreamOffset) {streamOffset = pstreamOffset;};
void setAtomOffset(off_t patomOffset) { atomOffset = patomOffset; };
void setStreamOffset(off_t pstreamOffset) { streamOffset = pstreamOffset; };
char *getAtomName();
@@ -134,20 +135,42 @@ public:
void setParent(AtomBase *pParent) {parentAtom = pParent;};
AtomBase *getParent() { return parentAtom;};
void Read(uint64 *value);
void Read(uint32 *value);
void Read(int32 *value);
void Read(uint16 *value);
void Read(uint8 *value);
void Read(char *value, uint32 maxread);
void Read(uint8 *value, uint32 maxread);
uint64 GetBits(uint64 buffer, uint8 startBit, uint8 totalBits);
uint32 GetBits(uint32 buffer, uint8 startBit, uint8 totalBits);
};
class FullAtom : public AtomBase {
public:
FullAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~FullAtom();
virtual void OnProcessMetaData();
uint8 getVersion() {return Version;};
uint8 getFlags1() {return Flags1;};
uint8 getFlags2() {return Flags2;};
uint8 getFlags3() {return Flags3;};
private:
uint8 Version;
uint8 Flags1;
uint8 Flags2;
uint8 Flags3;
};
class AtomContainer : public AtomBase {
/*
This is an Atom that contains other atoms. It has children that may be Containter Atoms or Standard Atoms
This is an Atom that contains other atoms. It has children that may be Container Atoms or Standard Atoms
*/
@@ -39,14 +39,13 @@ extern AtomBase *getAtom(BPositionIO *pStream);
MOVFileReader::MOVFileReader(BPositionIO *pStream)
{
theStream = pStream;
// Find Size of Stream, need to rethink this for non seekable streams
theStream->Seek(0,SEEK_END);
StreamSize = theStream->Position();
theStream->Seek(0,SEEK_SET);
TotalChildren = 0;
theMVHDAtom = NULL;
}
@@ -56,41 +55,52 @@ MOVFileReader::~MOVFileReader()
theMVHDAtom = NULL;
}
bool MOVFileReader::IsEndOfData(off_t pPosition)
bool
MOVFileReader::IsEndOfData(off_t position)
{
AtomBase *aAtomBase;
AtomBase* aAtomBase;
aAtomBase = GetChildAtom(uint32('mdat'),0);
if (aAtomBase) {
MDATAtom *aMdatAtom = dynamic_cast<MDATAtom *>(aAtomBase);
return pPosition >= aMdatAtom->getEOF();
// check all mdat atoms to make sure position is within one of them
for (uint32 index=0;index<CountChildAtoms('mdat');index++) {
aAtomBase = GetChildAtom(uint32('mdat'),index);
if ((aAtomBase) && (aAtomBase->getAtomSize() > 8)) {
MDATAtom *aMDATAtom = dynamic_cast<MDATAtom *>(aAtomBase);
if (position >= aMDATAtom->getAtomOffset() && position <= aMDATAtom->getEOF()) {
return false;
}
}
}
return true;
}
bool MOVFileReader::IsEndOfFile(off_t pPosition)
bool
MOVFileReader::IsEndOfFile(off_t position)
{
return (pPosition >= StreamSize);
return (position >= StreamSize);
}
bool MOVFileReader::IsEndOfFile()
bool
MOVFileReader::IsEndOfFile()
{
return (theStream->Position() >= StreamSize);
return theStream->Position() >= StreamSize;
}
bool MOVFileReader::AddChild(AtomBase *pChildAtom)
bool
MOVFileReader::AddChild(AtomBase *childAtom)
{
if (pChildAtom) {
atomChildren[TotalChildren++] = pChildAtom;
if (childAtom) {
atomChildren[TotalChildren++] = childAtom;
return true;
}
return false;
}
AtomBase *MOVFileReader::GetChildAtom(uint32 patomType, uint32 offset)
AtomBase *
MOVFileReader::GetChildAtom(uint32 patomType, uint32 offset)
{
for (uint32 i=0;i<TotalChildren;i++) {
for (uint32 i = 0; i < TotalChildren; i++) {
if (atomChildren[i]->IsType(patomType)) {
// found match, skip if offset non zero.
if (offset == 0) {
@@ -113,7 +123,8 @@ AtomBase *MOVFileReader::GetChildAtom(uint32 patomType, uint32 offset)
return NULL;
}
uint32 MOVFileReader::CountChildAtoms(uint32 patomType)
uint32
MOVFileReader::CountChildAtoms(uint32 patomType)
{
uint32 count = 0;
@@ -123,9 +134,10 @@ uint32 MOVFileReader::CountChildAtoms(uint32 patomType)
return count;
}
MVHDAtom *MOVFileReader::getMVHDAtom()
MVHDAtom*
MOVFileReader::getMVHDAtom()
{
AtomBase *aAtomBase;
AtomBase *aAtomBase;
if (theMVHDAtom == NULL) {
aAtomBase = GetChildAtom(uint32('mvhd'));
@@ -136,223 +148,11 @@ AtomBase *aAtomBase;
return theMVHDAtom;
}
uint32 MOVFileReader::getMovieTimeScale()
void
MOVFileReader::BuildSuperIndex()
{
return getMVHDAtom()->getTimeScale();
}
bigtime_t MOVFileReader::getMovieDuration()
{
return ((bigtime_t(getMVHDAtom()->getDuration()) * 1000000L) / getMovieTimeScale());
}
uint32 MOVFileReader::getStreamCount()
{
// count the number of tracks in the file
return (CountChildAtoms(uint32('trak')));
}
bigtime_t MOVFileReader::getVideoDuration(uint32 stream_index)
{
AtomBase *aAtomBase;
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
}
return 0;
}
bigtime_t MOVFileReader::getAudioDuration(uint32 stream_index)
{
AtomBase *aAtomBase;
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())) {
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
}
return 0;
}
bigtime_t MOVFileReader::getMaxDuration()
{
AtomBase *aAtomBase;
int32 video_index,audio_index;
video_index = -1;
audio_index = -1;
// find the active video and audio tracks
for (uint32 i=0;i<getStreamCount();i++) {
aAtomBase = GetChildAtom(uint32('trak'),i);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsActive())) {
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio()) {
audio_index = int32(i);
}
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo()) {
video_index = int32(i);
}
}
}
if ((video_index >= 0) && (audio_index >= 0)) {
return MAX(getVideoDuration(video_index),getAudioDuration(audio_index));
}
if ((video_index < 0) && (audio_index >= 0)) {
return getAudioDuration(audio_index);
}
if ((video_index >= 0) && (audio_index < 0)) {
return getVideoDuration(video_index);
}
return 0;
}
uint32 MOVFileReader::getVideoFrameCount(uint32 stream_index)
{
AtomBase *aAtomBase;
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
}
return 1;
}
uint32 MOVFileReader::getAudioFrameCount(uint32 stream_index)
{
if (IsAudio(stream_index)) {
return uint32(((getAudioDuration(stream_index) * AudioFormat(stream_index)->SampleRate) / 1000000L) + 0.5);
}
return 0;
}
bool MOVFileReader::IsVideo(uint32 stream_index)
{
// Look for a trak with a vmhd atom
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) {
return (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo());
}
// No trak
return false;
}
bool MOVFileReader::IsAudio(uint32 stream_index)
{
// Look for a trak with a smhd atom
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) {
return (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio());
}
// No trak
return false;
}
uint32 MOVFileReader::getFirstFrameInChunk(uint32 stream_index, uint32 pChunkID)
{
// Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
return aTrakAtom->getFirstSampleInChunk(pChunkID);
}
return 0;
}
uint32 MOVFileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
{
// Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
uint32 ChunkNo = 1;
if (IsAudio(stream_index)) {
ChunkNo = pFrameNo;
}
if (IsVideo(stream_index)) {
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
uint32 OffsetInChunk;
ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
}
return aTrakAtom->getNoSamplesInChunk(ChunkNo);
}
return 0;
}
uint64 MOVFileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
{
// Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
if (IsAudio(stream_index)) {
// FrameNo is really chunk No for audio
uint32 ChunkNo = pFrameNo;
// Get Offset For Chunk
return aTrakAtom->getOffsetForChunk(ChunkNo);
}
if (IsVideo(stream_index)) {
if (pFrameNo < aTrakAtom->FrameCount()) {
// Get Sample for Frame
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
// Get Chunk For Sample and the offset for the frame within that chunk
uint32 OffsetInChunk;
uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
// Get Offset For Chunk
uint64 OffsetNo = aTrakAtom->getOffsetForChunk(ChunkNo);
if (ChunkNo != 0) {
uint32 SampleSize;
// Adjust the Offset for the Offset in the chunk
if (aTrakAtom->IsSingleSampleSize()) {
SampleSize = aTrakAtom->getSizeForSample(SampleNo);
OffsetNo = OffsetNo + (OffsetInChunk * SampleSize);
} else {
// This is bad news performance wise
for (uint32 i=1;i<=OffsetInChunk;i++) {
SampleSize = aTrakAtom->getSizeForSample(SampleNo-i);
OffsetNo = OffsetNo + SampleSize;
}
}
}
return OffsetNo;
}
}
}
return 0;
}
void MOVFileReader::BuildSuperIndex()
{
AtomBase *aAtomBase;
AtomBase *aAtomBase;
for (uint32 stream=0;stream<getStreamCount();stream++) {
aAtomBase = GetChildAtom(uint32('trak'),stream);
@@ -363,7 +163,7 @@ AtomBase *aAtomBase;
}
}
}
// Add end of file to index
aAtomBase = GetChildAtom(uint32('mdat'),0);
if (aAtomBase) {
@@ -372,7 +172,215 @@ AtomBase *aAtomBase;
}
}
status_t MOVFileReader::ParseFile()
uint32
MOVFileReader::getMovieTimeScale()
{
return getMVHDAtom()->getTimeScale();
}
bigtime_t
MOVFileReader::getMovieDuration()
{
return bigtime_t((getMVHDAtom()->getDuration() * 1000000.0) / getMovieTimeScale());
}
uint32
MOVFileReader::getStreamCount()
{
// count the number of tracks in the file
return CountChildAtoms(uint32('trak'));
}
bigtime_t
MOVFileReader::getVideoDuration(uint32 streamIndex)
{
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())
return dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1);
return 0;
}
bigtime_t
MOVFileReader::getAudioDuration(uint32 streamIndex)
{
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())
return dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1);
return 0;
}
bigtime_t
MOVFileReader::getMaxDuration()
{
AtomBase *aAtomBase;
int32 videoIndex = -1;
int32 audioIndex = -1;
// find the active video and audio tracks
for (uint32 i = 0; i < getStreamCount(); i++) {
aAtomBase = GetChildAtom(uint32('trak'), i);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsActive())) {
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio()) {
audioIndex = int32(i);
}
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo()) {
videoIndex = int32(i);
}
}
}
if (videoIndex >= 0 && audioIndex >= 0) {
return max_c(getVideoDuration(videoIndex),
getAudioDuration(audioIndex));
}
if (videoIndex < 0 && audioIndex >= 0) {
return getAudioDuration(audioIndex);
}
if (videoIndex >= 0 && audioIndex < 0) {
return getVideoDuration(videoIndex);
}
return 0;
}
uint32
MOVFileReader::getFrameCount(uint32 streamIndex)
{
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase) {
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
}
return 1;
}
uint32
MOVFileReader::getAudioChunkCount(uint32 streamIndex)
{
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())
return dynamic_cast<TRAKAtom *>(aAtomBase)->getTotalChunks();
return 0;
}
bool
MOVFileReader::IsVideo(uint32 streamIndex)
{
// Look for a 'trak' with a vmhd atom
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase)
return dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo();
// No track
return false;
}
bool
MOVFileReader::IsAudio(uint32 streamIndex)
{
// Look for a 'trak' with a smhd atom
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase)
return dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio();
// No track
return false;
}
uint32
MOVFileReader::getFirstFrameInChunk(uint32 streamIndex, uint32 pChunkID)
{
// Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
return aTrakAtom->getFirstSampleInChunk(pChunkID);
}
return 0;
}
uint32
MOVFileReader::getNoFramesInChunk(uint32 streamIndex, uint32 pFrameNo)
{
// Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
uint32 ChunkNo = 1;
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
uint32 OffsetInChunk;
ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
return aTrakAtom->getNoSamplesInChunk(ChunkNo);
}
return 0;
}
uint64
MOVFileReader::getOffsetForFrame(uint32 streamIndex, uint32 pFrameNo)
{
// Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
if (pFrameNo < aTrakAtom->FrameCount()) {
// Get time for Frame
bigtime_t Time = aTrakAtom->getTimeForFrame(pFrameNo);
// Get Sample for Time
uint32 SampleNo = aTrakAtom->getSampleForTime(Time);
// Get Chunk For Sample and the offset for the frame within that chunk
uint32 OffsetInChunk;
uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
// Get Offset For Chunk
uint64 OffsetNo = aTrakAtom->getOffsetForChunk(ChunkNo);
if (ChunkNo != 0) {
uint32 SizeForSample;
// Adjust the Offset for the Offset in the chunk
if (aTrakAtom->IsSingleSampleSize()) {
SizeForSample = aTrakAtom->getSizeForSample(SampleNo);
OffsetNo = OffsetNo + (OffsetInChunk * SizeForSample);
} else {
// This is bad news performance wise
for (uint32 i=1;i<=OffsetInChunk;i++) {
SizeForSample = aTrakAtom->getSizeForSample(SampleNo-i);
OffsetNo = OffsetNo + SizeForSample;
}
}
}
printf("frame %ld, time %Ld, sample %ld, Chunk %ld, OffsetInChunk %ld, Offset %Ld\n",pFrameNo, Time, SampleNo, ChunkNo, OffsetInChunk, OffsetNo);
return OffsetNo;
}
}
return 0;
}
status_t
MOVFileReader::ParseFile()
{
AtomBase *aChild;
while (IsEndOfFile() == false) {
@@ -392,7 +400,8 @@ status_t MOVFileReader::ParseFile()
return B_OK;
}
const mov_main_header *MOVFileReader::MovMainHeader()
const mov_main_header*
MOVFileReader::MovMainHeader()
{
// Fill In theMainHeader
// uint32 micro_sec_per_frame;
@@ -428,22 +437,22 @@ const mov_main_header *MOVFileReader::MovMainHeader()
} else {
theMainHeader.width = VideoFormat(videoStream)->width;
theMainHeader.height = VideoFormat(videoStream)->height;
theMainHeader.total_frames = getVideoFrameCount(videoStream);
theMainHeader.total_frames = getFrameCount(videoStream);
theMainHeader.suggested_buffer_size = theMainHeader.width * theMainHeader.height * VideoFormat(videoStream)->bit_count / 8;
theMainHeader.micro_sec_per_frame = uint32(1000000.0 / VideoFormat(videoStream)->FrameRate);
}
theMainHeader.padding_granularity = 0;
theMainHeader.max_bytes_per_sec = 0;
return &theMainHeader;
}
const AudioMetaData *MOVFileReader::AudioFormat(uint32 stream_index)
const AudioMetaData *
MOVFileReader::AudioFormat(uint32 streamIndex)
{
if (IsAudio(stream_index)) {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (IsAudio(streamIndex)) {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
@@ -496,17 +505,16 @@ const AudioMetaData *MOVFileReader::AudioFormat(uint32 stream_index)
return NULL;
}
const VideoMetaData *MOVFileReader::VideoFormat(uint32 stream_index)
const VideoMetaData*
MOVFileReader::VideoFormat(uint32 streamIndex)
{
if (IsVideo(stream_index)) {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (IsVideo(streamIndex)) {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
aAtomBase = aTrakAtom->GetChildAtom(uint32('stsd'),0);
if (aAtomBase) {
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
@@ -540,29 +548,30 @@ const VideoMetaData *MOVFileReader::VideoFormat(uint32 stream_index)
return NULL;
}
const mov_stream_header *MOVFileReader::StreamFormat(uint32 stream_index)
const mov_stream_header*
MOVFileReader::StreamFormat(uint32 streamIndex)
{
// Fill In a Stream Header
theStreamHeader.length = 0;
if (IsActive(stream_index) == false) {
if (IsActive(streamIndex) == false) {
return NULL;
}
if (IsVideo(stream_index)) {
theStreamHeader.rate = uint32(1000000L*VideoFormat(stream_index)->FrameRate);
// Fill In a Stream Header
theStreamHeader.length = 0;
if (IsVideo(streamIndex)) {
theStreamHeader.rate = uint32(1000000.0*VideoFormat(streamIndex)->FrameRate);
theStreamHeader.scale = 1000000L;
theStreamHeader.length = getVideoFrameCount(stream_index);
theStreamHeader.length = getFrameCount(streamIndex);
}
if (IsAudio(stream_index)) {
theStreamHeader.rate = uint32(AudioFormat(stream_index)->SampleRate);
if (IsAudio(streamIndex)) {
theStreamHeader.rate = uint32(AudioFormat(streamIndex)->SampleRate);
theStreamHeader.scale = 1;
theStreamHeader.length = getAudioFrameCount(stream_index);
theStreamHeader.sample_size = AudioFormat(stream_index)->SampleSize;
theStreamHeader.suggested_buffer_size = theStreamHeader.rate * theStreamHeader.sample_size;
theStreamHeader.length = getFrameCount(streamIndex);
theStreamHeader.sample_size = AudioFormat(streamIndex)->SampleSize;
theStreamHeader.suggested_buffer_size = AudioFormat(streamIndex)->BufferSize;
}
return &theStreamHeader;
}
@@ -570,23 +579,14 @@ const mov_stream_header *MOVFileReader::StreamFormat(uint32 stream_index)
uint32
MOVFileReader::getChunkSize(uint32 streamIndex, uint32 frameNumber)
{
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase == NULL)
return 0;
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
if (IsAudio(streamIndex)) {
// We read audio in chunk by chunk so chunk size is chunk size
off_t chunkStart = aTrakAtom->getOffsetForChunk(frameNumber);
return theChunkSuperIndex.getChunkSize(streamIndex, frameNumber, chunkStart);
}
if (IsVideo(streamIndex)) {
if (frameNumber < aTrakAtom->FrameCount()) {
// We read video in Sample by Sample so chunk size is Sample Size
uint32 sampleNumber = aTrakAtom->getSampleForFrame(frameNumber);
return aTrakAtom->getSizeForSample(sampleNumber);
uint32 SampleNo = aTrakAtom->getSampleForFrame(frameNumber);
return aTrakAtom->getSizeForSample(SampleNo);
}
}
@@ -595,57 +595,62 @@ MOVFileReader::getChunkSize(uint32 streamIndex, uint32 frameNumber)
bool
MOVFileReader::IsKeyFrame(uint32 stream_index, uint32 pFrameNo)
MOVFileReader::IsKeyFrame(uint32 streamIndex, uint32 pFrameNo)
{
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
return aTrakAtom->IsSyncSample(SampleNo);
return aTrakAtom->IsSyncSample(pFrameNo);
}
return false;
}
bool MOVFileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t *start, uint32 *size, bool *keyframe)
bool
MOVFileReader::GetNextChunkInfo(uint32 streamIndex, uint32 pFrameNo,
off_t *start, uint32 *size, bool *keyframe)
{
*start = getOffsetForFrame(stream_index, pFrameNo);
*size = getChunkSize(stream_index, pFrameNo);
*start = getOffsetForFrame(streamIndex, pFrameNo);
*size = getChunkSize(streamIndex, pFrameNo);
if ((*start > 0) && (*size > 0)) {
*keyframe = IsKeyFrame(stream_index, pFrameNo);
*keyframe = IsKeyFrame(streamIndex, pFrameNo);
}
return ((*start > 0) && (*size > 0) && !(IsEndOfFile(*start + *size)) && !(IsEndOfData(*start + *size)));
// printf("start %Ld, size %ld, eof %s, eod %s\n",*start,*size, IsEndOfFile(*start + *size) ? "true" : "false", IsEndOfData(*start + *size) ? "true" : "false");
// TODO need a better method for detecting End of Data Note ChunkSize of 0 seems to be it.
return *start > 0 && *size > 0 && !IsEndOfFile(*start + *size)
&& !IsEndOfData(*start + *size);
}
bool MOVFileReader::IsActive(uint32 stream_index)
bool
MOVFileReader::IsActive(uint32 streamIndex)
{
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),streamIndex);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
return aTrakAtom->IsActive();
}
return false;
}
/* static */
bool MOVFileReader::IsSupported(BPositionIO *source)
bool
MOVFileReader::IsSupported(BPositionIO *source)
{
// MOV files normally do not have ftyp atoms
// But when they do we need to check if they have a qt brand
// No qt brand means the file is likely to be a MP4 file
AtomBase *aAtom;
aAtom = getAtom(source);
AtomBase *aAtom = getAtom(source);
if (aAtom) {
if (dynamic_cast<FTYPAtom *>(aAtom)) {
printf("ftyp atom found checking for qt brand\n");
aAtom->ProcessMetaData();
printf("ftyp atom found checking for qt brand\n");
// MP4 files start with a ftyp atom that contains an isom brand
// MOV files with a ftyp atom contain the qt brand
return dynamic_cast<FTYPAtom *>(aAtom)->HasBrand(uint32('qt '));
@@ -33,7 +33,7 @@
#include "MOVParser.h"
#include "ChunkSuperIndex.h"
// QT MOV file reader (and maybe MP4 as well)
// QT MOV file reader
class MOVFileReader {
private:
// Atom List
@@ -68,9 +68,9 @@ public:
// getter for MVHDAtom
MVHDAtom *getMVHDAtom();
bool IsEndOfFile(off_t pPosition);
bool IsEndOfFile(off_t position);
bool IsEndOfFile();
bool IsEndOfData(off_t pPosition);
bool IsEndOfData(off_t position);
// Is this a quicktime file
static bool IsSupported(BPositionIO *source);
@@ -81,45 +81,44 @@ public:
// Duration defined by the movie header
bigtime_t getMovieDuration();
// The first video track duration indexed by stream_index
bigtime_t getVideoDuration(uint32 stream_index);
// the first audio track duration indexed by stream_index
bigtime_t getAudioDuration(uint32 stream_index);
// The first video track duration indexed by streamIndex
bigtime_t getVideoDuration(uint32 streamIndex);
// the first audio track duration indexed by streamIndex
bigtime_t getAudioDuration(uint32 streamIndex);
// the max of all active audio or video durations
bigtime_t getMaxDuration();
// The no of frames in the video track indexed by stream_index
uint32 getVideoFrameCount(uint32 stream_index);
// The no of frames in the audio track indexed by stream_index
uint32 getAudioFrameCount(uint32 stream_index);
// The no of frames in the track indexed by streamIndex
uint32 getFrameCount(uint32 streamIndex);
// The no of chunks in the audio track indexed by streamIndex
uint32 getAudioChunkCount(uint32 streamIndex);
// Is stream (track) a video track
bool IsVideo(uint32 stream_index);
bool IsVideo(uint32 streamIndex);
// Is stream (track) a audio track
bool IsAudio(uint32 stream_index);
bool IsAudio(uint32 streamIndex);
uint32 getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo);
uint32 getFirstFrameInChunk(uint32 stream_index, uint32 pChunkID);
uint32 getNoFramesInChunk(uint32 streamIndex, uint32 pFrameNo);
uint32 getFirstFrameInChunk(uint32 streamIndex, uint32 pChunkID);
uint64 getOffsetForFrame(uint32 stream_index, uint32 pFrameNo);
uint32 getChunkSize(uint32 stream_index, uint32 pFrameNo);
bool IsKeyFrame(uint32 stream_index, uint32 pFrameNo);
uint64 getOffsetForFrame(uint32 streamIndex, uint32 pFrameNo);
uint32 getChunkSize(uint32 streamIndex, uint32 pFrameNo);
bool IsKeyFrame(uint32 streamIndex, uint32 pFrameNo);
status_t ParseFile();
BPositionIO *Source() {return theStream;};
bool IsActive(uint32 stream_index);
bool IsActive(uint32 streamIndex);
bool GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t *start, uint32 *size, bool *keyframe);
bool GetNextChunkInfo(uint32 streamIndex, uint32 pFrameNo, off_t *start, uint32 *size, bool *keyframe);
// Return all Audio Meta Data
const AudioMetaData *AudioFormat(uint32 stream_index);
const AudioMetaData *AudioFormat(uint32 streamIndex);
// Return all Video Meta Data
const VideoMetaData *VideoFormat(uint32 stream_index);
const VideoMetaData *VideoFormat(uint32 streamIndex);
// XXX these need work
const mov_main_header *MovMainHeader();
const mov_stream_header *StreamFormat(uint32 stream_index);
const mov_stream_header *StreamFormat(uint32 streamIndex);
};
#endif
@@ -57,6 +57,10 @@ AtomBase *getAtom(BPositionIO *pStream)
// Handle extended size
pStream->Read(&aRealAtomSize,4);
aRealAtomSize = B_BENDIAN_TO_HOST_INT64(aRealAtomSize);
} else if (aAtomSize == 0) {
// aAtomSize extends to end of file.
// TODO this is broken
aRealAtomSize = 0;
} else {
aRealAtomSize = aAtomSize;
}
@@ -157,10 +161,22 @@ AtomBase *getAtom(BPositionIO *pStream)
return new STSSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
if (aAtomType == uint32('ctts')) {
return new CTTSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
if (aAtomType == uint32('stsz')) {
return new STSZAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
if (aAtomType == uint32('stz2')) {
return new STZ2Atom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
if (aAtomType == uint32('ftyp')) {
return new FTYPAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
if (aAtomType == uint32('cmov')) {
return new CMOVAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
@@ -177,10 +193,6 @@ AtomBase *getAtom(BPositionIO *pStream)
return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
if (aAtomType == uint32('ftyp')) {
return new FTYPAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
@@ -365,7 +377,7 @@ char *CMVDAtom::OnGetAtomName()
return "Compressed Movie Data";
}
MVHDAtom::MVHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
MVHDAtom::MVHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
}
@@ -375,6 +387,7 @@ MVHDAtom::~MVHDAtom()
void MVHDAtom::OnProcessMetaData()
{
FullAtom::OnProcessMetaData();
Read(&theHeader.CreationTime);
Read(&theHeader.ModificationTime);
Read(&theHeader.TimeScale);
@@ -387,7 +400,7 @@ void MVHDAtom::OnProcessMetaData()
Read(&theHeader.SelectionTime);
Read(&theHeader.SelectionDuration);
Read(&theHeader.CurrentTime);
Read(&theHeader.NextTrackID);
Read(&theHeader.NextTrackID);
}
char *MVHDAtom::OnGetAtomName()
@@ -408,7 +421,7 @@ AtomBase *aAtomBase;
return theMVHDAtom;
}
STTSAtom::STTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
STTSAtom::STTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
theHeader.NoEntries = 0;
SUMDurations = 0;
@@ -427,8 +440,12 @@ void STTSAtom::OnProcessMetaData()
{
TimeToSample *aTimeToSample;
FullAtom::OnProcessMetaData();
ReadArrayHeader(&theHeader);
// printf("STTS:: Entries %ld\n",theHeader.NoEntries);
for (uint32 i=0;i<theHeader.NoEntries;i++) {
aTimeToSample = new TimeToSample;
@@ -438,7 +455,11 @@ TimeToSample *aTimeToSample;
theTimeToSampleArray[i] = aTimeToSample;
SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
SUMCounts += theTimeToSampleArray[i]->Count;
// printf("(%ld,%ld)",aTimeToSample->Count,aTimeToSample->Duration);
}
// printf("\n");
}
char *STTSAtom::OnGetAtomName()
@@ -446,28 +467,55 @@ char *STTSAtom::OnGetAtomName()
return "Time to Sample Atom";
}
uint32 STTSAtom::getSampleForTime(uint32 pTime)
uint32 STTSAtom::getSampleForTime(bigtime_t pTime)
{
// TODO this is too slow. PreCalc when loading this?
uint64 Duration = 0;
for (uint32 i=0;i<theHeader.NoEntries;i++) {
Duration += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
if (Duration > pTime) {
return i;
}
}
return 0;
// Sample for time is this calc, how does STTS help us?
return uint32((pTime * FrameRate + 50) / 1000000.0);
}
uint32 STTSAtom::getSampleForFrame(uint32 pFrame)
{
// Hmm Sample is Frame really, this Atom is more usefull for time->sample calcs
// Convert frame to time and call getSampleForTime()
return pFrame;
}
STSCAtom::STSCAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
CTTSAtom::CTTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
theHeader.NoEntries = 0;
}
CTTSAtom::~CTTSAtom()
{
for (uint32 i=0;i<theHeader.NoEntries;i++) {
delete theCompTimeToSampleArray[i];
theCompTimeToSampleArray[i] = NULL;
}
}
void CTTSAtom::OnProcessMetaData()
{
CompTimeToSample *aCompTimeToSample;
FullAtom::OnProcessMetaData();
ReadArrayHeader(&theHeader);
for (uint32 i=0;i<theHeader.NoEntries;i++) {
aCompTimeToSample = new CompTimeToSample;
Read(&aCompTimeToSample->Count);
Read(&aCompTimeToSample->Offset);
theCompTimeToSampleArray[i] = aCompTimeToSample;
}
}
char *CTTSAtom::OnGetAtomName()
{
return "Composition Time to Sample Atom";
}
STSCAtom::STSCAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
theHeader.NoEntries = 0;
}
@@ -484,9 +532,13 @@ void STSCAtom::OnProcessMetaData()
{
SampleToChunk *aSampleToChunk;
FullAtom::OnProcessMetaData();
ReadArrayHeader(&theHeader);
uint32 TotalPrevSamples = 0;
// printf("STSC:: Entries %ld\n",theHeader.NoEntries);
for (uint32 i=0;i<theHeader.NoEntries;i++) {
aSampleToChunk = new SampleToChunk;
@@ -502,8 +554,11 @@ SampleToChunk *aSampleToChunk;
aSampleToChunk->TotalPrevSamples = 0;
}
// printf("(%ld,%ld)",aSampleToChunk->SamplesPerChunk, aSampleToChunk->TotalPrevSamples);
theSampleToChunkArray[i] = aSampleToChunk;
}
// printf("\n");
}
char *STSCAtom::OnGetAtomName()
@@ -559,7 +614,7 @@ uint32 STSCAtom::getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk)
return theSampleToChunkArray[theHeader.NoEntries-1]->FirstChunk;
}
STSSAtom::STSSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
STSSAtom::STSSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
theHeader.NoEntries = 0;
}
@@ -576,12 +631,15 @@ void STSSAtom::OnProcessMetaData()
{
SyncSample *aSyncSample;
FullAtom::OnProcessMetaData();
ReadArrayHeader(&theHeader);
for (uint32 i=0;i<theHeader.NoEntries;i++) {
aSyncSample = new SyncSample;
Read(&aSyncSample->SyncSampleNo);
theSyncSampleArray[i] = aSyncSample;
}
}
@@ -599,7 +657,7 @@ bool STSSAtom::IsSyncSample(uint32 pSampleNo)
return true;
}
if (pSampleNo > theSyncSampleArray[i]->SyncSampleNo) {
if (pSampleNo < theSyncSampleArray[i]->SyncSampleNo) {
return false;
}
}
@@ -607,14 +665,14 @@ bool STSSAtom::IsSyncSample(uint32 pSampleNo)
return false;
}
STSZAtom::STSZAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
STSZAtom::STSZAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
theHeader.NoEntries = 0;
SampleCount = 0;
}
STSZAtom::~STSZAtom()
{
for (uint32 i=0;i<theHeader.NoEntries;i++) {
for (uint32 i=0;i<SampleCount;i++) {
delete theSampleSizeArray[i];
theSampleSizeArray[i] = NULL;
}
@@ -622,38 +680,36 @@ STSZAtom::~STSZAtom()
void STSZAtom::OnProcessMetaData()
{
SampleSizeEntry *aSampleSize;
FullAtom::OnProcessMetaData();
Read(&SampleSize);
Read(&SampleCount);
// Just to make things difficult this is not quite a standard array header
Read(&theHeader.Version);
Read(&theHeader.Flags1);
Read(&theHeader.Flags2);
Read(&theHeader.Flags3);
Read(&theHeader.SampleSize);
Read(&theHeader.NoEntries);
// If the sample size is constant there is no array and NoEntries seems to contain bad values
if (theHeader.SampleSize == 0) {
for (uint32 i=0;i<theHeader.NoEntries;i++) {
aSampleSize = new SampleSizeEntry;
if (SampleSize == 0) {
SampleSizePtr aSampleSizePtr;
for (uint32 i=0;i<SampleCount;i++) {
aSampleSizePtr = new SampleSizeEntry;
Read(&aSampleSize->EntrySize);
theSampleSizeArray[i] = aSampleSize;
Read(&aSampleSizePtr->EntrySize);
theSampleSizeArray[i] = aSampleSizePtr;
}
}
}
char *STSZAtom::OnGetAtomName()
{
printf("%ld ",theHeader.SampleSize);
printf("SS=%ld Count=%ld ",SampleSize,SampleCount);
return "Sample Size Atom";
}
uint32 STSZAtom::getSizeForSample(uint32 pSampleNo)
{
if (theHeader.SampleSize > 0) {
if (SampleSize > 0) {
// All samples are the same size
return theHeader.SampleSize;
return SampleSize;
}
// Sample Array indexed by SampleNo
@@ -662,10 +718,96 @@ uint32 STSZAtom::getSizeForSample(uint32 pSampleNo)
bool STSZAtom::IsSingleSampleSize()
{
return (theHeader.SampleSize > 0);
return (SampleSize > 0);
}
STCOAtom::STCOAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
STZ2Atom::STZ2Atom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
SampleCount = 0;
}
STZ2Atom::~STZ2Atom()
{
for (uint32 i=0;i<SampleCount;i++) {
delete theSampleSizeArray[i];
theSampleSizeArray[i] = NULL;
}
}
void STZ2Atom::OnProcessMetaData()
{
FullAtom::OnProcessMetaData();
uint8 reserved;
Read(&reserved);
Read(&reserved);
Read(&reserved);
Read(&FieldSize);
Read(&SampleCount);
SampleSizePtr aSampleSizePtr;
uint8 EntrySize8;
uint16 EntrySize16;
for (uint32 i=0;i<SampleCount;i++) {
aSampleSizePtr = new SampleSizeEntry;
switch (FieldSize) {
case 4:
Read(&EntrySize8);
// 2 values per byte
aSampleSizePtr->EntrySize = (uint32)(EntrySize8);
break;
case 8:
Read(&EntrySize8);
// 1 value per byte
aSampleSizePtr->EntrySize = (uint32)(EntrySize8);
break;
case 16:
Read(&EntrySize16);
// 1 value per 2 bytes
aSampleSizePtr->EntrySize = (uint32)(EntrySize16);
break;
}
theSampleSizeArray[i] = aSampleSizePtr;
}
}
char *STZ2Atom::OnGetAtomName()
{
return "Compressed Sample Size Atom";
}
uint32 STZ2Atom::getSizeForSample(uint32 pSampleNo)
{
// THIS CODE NEEDS SOME TESTING, never seen a STZ2 atom
uint32 index;
if (FieldSize == 4) {
// 2 entries per array entry so Divide by 2
index = pSampleNo / 2;
if (index * 2 == pSampleNo) {
// even so return low nibble
return theSampleSizeArray[index]->EntrySize && 0x0000000f;
} else {
// odd so return high nibble
return theSampleSizeArray[index]->EntrySize && 0x000000f0;
}
}
// Sample Array indexed by SampleNo
return theSampleSizeArray[pSampleNo]->EntrySize;
}
bool STZ2Atom::IsSingleSampleSize()
{
return false;
}
STCOAtom::STCOAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
theHeader.NoEntries = 0;
}
@@ -692,6 +834,8 @@ void STCOAtom::OnProcessMetaData()
{
ChunkToOffset *aChunkToOffset;
FullAtom::OnProcessMetaData();
ReadArrayHeader(&theHeader);
for (uint32 i=0;i<theHeader.NoEntries;i++) {
@@ -718,8 +862,8 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
}
#if DEBUG
char msg[100]; sprintf(msg, "Bad Chunk ID %ld / %ld\n", pChunkID, theHeader.NoEntries);
DEBUGGER(msg);
char msg[100]; sprintf(msg, "Bad Chunk ID %ld / %ld\n", pChunkID, theHeader.NoEntries);
DEBUGGER(msg);
#endif
TRESPASS();
@@ -754,7 +898,7 @@ char *ESDSAtom::OnGetAtomName()
return "Extended Sample Description Atom";
}
STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
theHeader.NoEntries = 0;
}
@@ -786,7 +930,7 @@ STSDAtom::~STSDAtom()
uint32 STSDAtom::getMediaComponentSubType()
{
return dynamic_cast<STBLAtom *>(getParent())->getMediaComponentSubType();
return dynamic_cast<STBLAtom *>(getParent())->getMediaHandlerType();
}
void STSDAtom::ReadSoundDescription()
@@ -945,6 +1089,9 @@ void STSDAtom::ReadVideoDescription()
void STSDAtom::OnProcessMetaData()
{
FullAtom::OnProcessMetaData();
ReadArrayHeader(&theHeader);
for (uint32 i=0;i<theHeader.NoEntries;i++) {
@@ -1121,12 +1268,13 @@ void MDATAtom::OnProcessMetaData()
char *MDATAtom::OnGetAtomName()
{
printf("Offset %lld, Size %lld ",getAtomOffset(),getAtomSize() - 8);
return "Media Data Atom";
}
off_t MDATAtom::getEOF()
{
return getStreamOffset() + getAtomSize();
return getAtomOffset() + getAtomSize() - 8;
}
MINFAtom::MINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
@@ -1146,9 +1294,9 @@ char *MINFAtom::OnGetAtomName()
return "Quicktime Media Information Atom";
}
uint32 MINFAtom::getMediaComponentSubType()
uint32 MINFAtom::getMediaHandlerType()
{
return dynamic_cast<MDIAAtom *>(getParent())->getMediaComponentSubType();
return dynamic_cast<MDIAAtom *>(getParent())->getMediaHandlerType();
}
STBLAtom::STBLAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
@@ -1168,9 +1316,9 @@ char *STBLAtom::OnGetAtomName()
return "Quicktime Sample Table Atom";
}
uint32 STBLAtom::getMediaComponentSubType()
uint32 STBLAtom::getMediaHandlerType()
{
return dynamic_cast<MINFAtom *>(getParent())->getMediaComponentSubType();
return dynamic_cast<MINFAtom *>(getParent())->getMediaHandlerType();
}
DINFAtom::DINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
@@ -1190,7 +1338,7 @@ char *DINFAtom::OnGetAtomName()
return "Quicktime Data Information Atom";
}
TKHDAtom::TKHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
TKHDAtom::TKHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
}
@@ -1200,15 +1348,11 @@ TKHDAtom::~TKHDAtom()
void TKHDAtom::OnProcessMetaData()
{
Read(&Version);
FullAtom::OnProcessMetaData();
if (Version == 0) {
// Read into V0 header and convert to V1 Header
if (getVersion() == 0) {
tkhdV0 aHeaderV0;
Read(&aHeaderV0.Flags1);
Read(&aHeaderV0.Flags2);
Read(&aHeaderV0.Flags3);
Read(&aHeaderV0.CreationTime);
Read(&aHeaderV0.ModificationTime);
Read(&aHeaderV0.TrackID);
@@ -1219,26 +1363,23 @@ void TKHDAtom::OnProcessMetaData()
Read(&aHeaderV0.AlternateGroup);
Read(&aHeaderV0.Volume);
Read(&aHeaderV0.Reserved3);
Read(aHeaderV0.MatrixStructure,36);
for (uint32 i=0;i<9;i++) {
Read(&theHeader.MatrixStructure[i]);
}
Read(&aHeaderV0.TrackWidth);
Read(&aHeaderV0.TrackHeight);
theHeader.Flags1 = aHeaderV0.Flags1;
theHeader.Flags2 = aHeaderV0.Flags2;
theHeader.Flags3 = aHeaderV0.Flags3;
theHeader.Reserved1 = aHeaderV0.Reserved1;
theHeader.Reserved2 = aHeaderV0.Reserved2;
theHeader.Reserved3 = aHeaderV0.Reserved3;
for (uint32 i=0;i<36;i++) {
theHeader.MatrixStructure[i] = aHeaderV0.MatrixStructure[i];
}
// upconvert to V1 header
theHeader.CreationTime = uint64(aHeaderV0.CreationTime);
theHeader.ModificationTime = uint64(aHeaderV0.ModificationTime);
theHeader.CreationTime = (uint64)(aHeaderV0.CreationTime);
theHeader.ModificationTime = (uint64)(aHeaderV0.ModificationTime);
theHeader.TrackID = aHeaderV0.TrackID;
theHeader.Duration = aHeaderV0.Duration;
theHeader.Duration = (uint64)(aHeaderV0.Duration);
theHeader.Layer = aHeaderV0.Layer;
theHeader.AlternateGroup = aHeaderV0.AlternateGroup;
theHeader.Volume = aHeaderV0.Volume;
@@ -1246,10 +1387,6 @@ void TKHDAtom::OnProcessMetaData()
theHeader.TrackHeight = aHeaderV0.TrackHeight;
} else {
// Read direct into V1 Header
Read(&theHeader.Flags1);
Read(&theHeader.Flags2);
Read(&theHeader.Flags3);
Read(&theHeader.CreationTime);
Read(&theHeader.ModificationTime);
Read(&theHeader.TrackID);
@@ -1260,7 +1397,11 @@ void TKHDAtom::OnProcessMetaData()
Read(&theHeader.AlternateGroup);
Read(&theHeader.Volume);
Read(&theHeader.Reserved3);
Read(theHeader.MatrixStructure,36);
for (uint32 i=0;i<9;i++) {
Read(&theHeader.MatrixStructure[i]);
}
Read(&theHeader.TrackWidth);
Read(&theHeader.TrackHeight);
}
@@ -1289,20 +1430,20 @@ char *MDIAAtom::OnGetAtomName()
return "Quicktime Media Atom";
}
uint32 MDIAAtom::getMediaComponentSubType()
uint32 MDIAAtom::getMediaHandlerType()
{
// get child atom hdlr
HDLRAtom *aHDLRAtom;
aHDLRAtom = dynamic_cast<HDLRAtom *>(GetChildAtom(uint32('hdlr')));
if (aHDLRAtom) {
return aHDLRAtom->getMediaComponentSubType();
return aHDLRAtom->getMediaHandlerType();
}
return 0;
}
MDHDAtom::MDHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
MDHDAtom::MDHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
}
@@ -1312,10 +1453,7 @@ MDHDAtom::~MDHDAtom()
void MDHDAtom::OnProcessMetaData()
{
Read(&theHeader.Version);
Read(&theHeader.Flags1);
Read(&theHeader.Flags2);
Read(&theHeader.Flags3);
FullAtom::OnProcessMetaData();
Read(&theHeader.CreationTime);
Read(&theHeader.ModificationTime);
Read(&theHeader.TimeScale);
@@ -1331,7 +1469,7 @@ char *MDHDAtom::OnGetAtomName()
bigtime_t MDHDAtom::getDuration()
{
return bigtime_t((uint64(theHeader.Duration) * 1000000L) / theHeader.TimeScale);
return bigtime_t((theHeader.Duration * 1000000.0) / theHeader.TimeScale);
}
uint32 MDHDAtom::getTimeScale()
@@ -1339,27 +1477,30 @@ uint32 MDHDAtom::getTimeScale()
return theHeader.TimeScale;
}
HDLRAtom::HDLRAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
HDLRAtom::HDLRAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
name = NULL;
}
HDLRAtom::~HDLRAtom()
{
if (name) {
free(name);
}
}
void HDLRAtom::OnProcessMetaData()
{
Read(&theHeader.Version);
Read(&theHeader.Flags1);
Read(&theHeader.Flags2);
Read(&theHeader.Flags3);
FullAtom::OnProcessMetaData();
Read(&theHeader.ComponentType);
Read(&theHeader.ComponentSubType);
Read(&theHeader.ComponentManufacturer);
Read(&theHeader.ComponentFlags);
Read(&theHeader.ComponentFlagsMask);
// Read Array of Strings?
name = (char *)(malloc(getBytesRemaining()));
Read(name,getBytesRemaining());
}
char *HDLRAtom::OnGetAtomName()
@@ -1377,12 +1518,12 @@ bool HDLRAtom::IsAudioHandler()
return (theHeader.ComponentSubType == 'soun');
}
uint32 HDLRAtom::getMediaComponentSubType()
uint32 HDLRAtom::getMediaHandlerType()
{
return theHeader.ComponentSubType;
}
VMHDAtom::VMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
VMHDAtom::VMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
}
@@ -1392,15 +1533,11 @@ VMHDAtom::~VMHDAtom()
void VMHDAtom::OnProcessMetaData()
{
vmhd aHeader;
Read(&aHeader.Version);
Read(&aHeader.Flags1);
Read(&aHeader.Flags2);
Read(&aHeader.Flags3);
Read(&aHeader.GraphicsMode);
Read(&aHeader.OpColourRed);
Read(&aHeader.OpColourGreen);
Read(&aHeader.OpColourBlue);
FullAtom::OnProcessMetaData();
Read(&theHeader.GraphicsMode);
Read(&theHeader.OpColourRed);
Read(&theHeader.OpColourGreen);
Read(&theHeader.OpColourBlue);
}
char *VMHDAtom::OnGetAtomName()
@@ -1408,7 +1545,7 @@ char *VMHDAtom::OnGetAtomName()
return "Quicktime Video Media Header";
}
SMHDAtom::SMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
SMHDAtom::SMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
{
}
@@ -1418,13 +1555,9 @@ SMHDAtom::~SMHDAtom()
void SMHDAtom::OnProcessMetaData()
{
smhd aHeader;
Read(&aHeader.Version);
Read(&aHeader.Flags1);
Read(&aHeader.Flags2);
Read(&aHeader.Flags3);
Read(&aHeader.Balance);
Read(&aHeader.Reserved);
FullAtom::OnProcessMetaData();
Read(&theHeader.Balance);
Read(&theHeader.Reserved);
}
char *SMHDAtom::OnGetAtomName()
@@ -26,8 +26,6 @@
#define _MOV_PARSER_H
#include "MOVAtom.h"
#include <File.h>
#include <MediaDefs.h>
#include <MediaFormats.h>
@@ -35,7 +33,10 @@
#include <map>
#include "MOVAtom.h"
typedef CompTimeToSample* CompTimeToSamplePtr;
typedef std::map<uint32, CompTimeToSamplePtr, std::less<uint32> > CompTimeToSampleArray;
typedef SoundDescriptionV1* SoundDescPtr;
typedef std::map<uint32, SoundDescPtr, std::less<uint32> > SoundDescArray;
typedef VideoDescriptionV0* VideoDescPtr;
@@ -48,11 +49,11 @@ typedef ChunkToOffset* ChunkToOffsetPtr;
typedef std::map<uint32, ChunkToOffsetPtr, std::less<uint32> > ChunkToOffsetArray;
typedef SyncSample* SyncSamplePtr;
typedef std::map<uint32, SyncSamplePtr, std::less<uint32> > SyncSampleArray;
typedef SampleSizeEntry* SampleSizeEntryPtr;
typedef std::map<uint32, SampleSizeEntryPtr, std::less<uint32> > SampleSizeArray;
typedef SampleSizeEntry* SampleSizePtr;
typedef std::map<uint32, SampleSizePtr, std::less<uint32> > SampleSizeArray;
// Atom class for reading the movie header atom
class MVHDAtom : public AtomBase {
class MVHDAtom : public FullAtom {
public:
MVHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~MVHDAtom();
@@ -121,6 +122,22 @@ private:
uint8 *Buffer;
};
// Atom class for reading the ftyp atom
class FTYPAtom : public AtomBase {
public:
FTYPAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~FTYPAtom();
void OnProcessMetaData();
char *OnGetAtomName();
bool HasBrand(uint32 brand);
private:
uint32 major_brand;
uint32 minor_version;
uint32 compatable_brands[32]; // Should be infinite but we will settle for max 32
uint32 total_brands;
};
// Atom class for reading the wide atom
class WIDEAtom : public AtomBase {
public:
@@ -152,26 +169,42 @@ public:
};
// Atom class for reading the time to sample atom
class STTSAtom : public AtomBase {
class STTSAtom : public FullAtom {
public:
STTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~STTSAtom();
void OnProcessMetaData();
char *OnGetAtomName();
uint64 getSUMCounts() {return SUMCounts;};
uint64 getSUMDurations() {return SUMDurations;};
uint32 getSampleForTime(uint32 pTime);
uint64 getSUMCounts() { return SUMCounts; };
bigtime_t getSUMDurations() { return SUMDurations; };
uint32 getSampleForTime(bigtime_t pTime);
uint32 getSampleForFrame(uint32 pFrame);
void setFrameRate(float pFrameRate) { FrameRate = pFrameRate; };
private:
array_header theHeader;
TimeToSampleArray theTimeToSampleArray;
uint64 SUMDurations;
bigtime_t SUMDurations;
uint64 SUMCounts;
float FrameRate;
};
// Atom class for reading the composition time to sample atom
class CTTSAtom : public FullAtom {
public:
CTTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~CTTSAtom();
void OnProcessMetaData();
char *OnGetAtomName();
private:
array_header theHeader;
CompTimeToSampleArray theCompTimeToSampleArray;
};
// Atom class for reading the sample to chunk atom
class STSCAtom : public AtomBase {
class STSCAtom : public FullAtom {
public:
STSCAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~STSCAtom();
@@ -187,7 +220,7 @@ private:
};
// Atom class for reading the chunk to offset atom
class STCOAtom : public AtomBase {
class STCOAtom : public FullAtom {
public:
STCOAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~STCOAtom();
@@ -207,7 +240,7 @@ private:
};
// Atom class for reading the sync sample atom
class STSSAtom : public AtomBase {
class STSSAtom : public FullAtom {
public:
STSSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~STSSAtom();
@@ -221,7 +254,7 @@ private:
};
// Atom class for reading the sample size atom
class STSZAtom : public AtomBase {
class STSZAtom : public FullAtom {
public:
STSZAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~STSZAtom();
@@ -231,7 +264,27 @@ public:
uint32 getSizeForSample(uint32 pSampleNo);
bool IsSingleSampleSize();
private:
SampleSizeHeader theHeader;
uint32 SampleSize;
uint32 SampleCount;
SampleSizeArray theSampleSizeArray;
};
// Atom class for reading the sample size 2 atom
class STZ2Atom : public FullAtom {
public:
STZ2Atom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~STZ2Atom();
void OnProcessMetaData();
char *OnGetAtomName();
uint32 getSizeForSample(uint32 pSampleNo);
bool IsSingleSampleSize();
private:
uint32 SampleSize;
uint32 SampleCount;
uint8 FieldSize;
SampleSizeArray theSampleSizeArray;
};
@@ -268,7 +321,7 @@ private:
};
// Atom class for reading the sdst atom
class STSDAtom : public AtomBase {
class STSDAtom : public FullAtom {
public:
STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~STSDAtom();
@@ -290,7 +343,7 @@ private:
};
// Atom class for reading the track header atom
class TKHDAtom : public AtomBase {
class TKHDAtom : public FullAtom {
public:
TKHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~TKHDAtom();
@@ -304,18 +357,16 @@ public:
// 0x002 Track in Movie
// 0x004 Track in Preview
// 0x008 Track in Poster
// It seems active tracks have all 4 flags set?
bool IsActive() {return ((theHeader.Flags3 == 0x0f) || (theHeader.Flags3 == 0x03));};
bool IsActive() {return ((getFlags3() && 0x01) || (getFlags3() && 0x0f));};
private:
tkhdV1 theHeader;
uint8 Version;
};
// Atom class for reading the media header atom
class MDHDAtom : public AtomBase {
class MDHDAtom : public FullAtom {
public:
MDHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~MDHDAtom();
@@ -332,23 +383,27 @@ private:
};
// Atom class for reading the video media header atom
class VMHDAtom : public AtomBase {
class VMHDAtom : public FullAtom {
public:
VMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~VMHDAtom();
void OnProcessMetaData();
char *OnGetAtomName();
bool IsCopyMode() {return theHeader.GraphicsMode == 0;};
private:
vmhd theHeader ;
};
// Atom class for reading the sound media header atom
class SMHDAtom : public AtomBase {
class SMHDAtom : public FullAtom {
public:
SMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~SMHDAtom();
void OnProcessMetaData();
char *OnGetAtomName();
private:
smhd theHeader;
};
// Atom class for reading the track atom
@@ -361,14 +416,15 @@ public:
void OnChildProcessingComplete();
bigtime_t Duration(uint32 TimeScale); // Return duration of track
uint32 FrameCount() {return framecount;};
bigtime_t Duration() { return Duration(timescale); }
uint32 FrameCount() { return framecount; };
bool IsVideo(); // Is this a video track
bool IsAudio(); // Is this a audio track
// GetAudioMetaData() // If this is a audio track get the audio meta data
// GetVideoMetaData() // If this is a video track get the video meta data
uint32 getTimeForFrame(uint32 pFrame, uint32 pTimeScale);
uint32 getSampleForTime(uint32 pTime);
bigtime_t getTimeForFrame(uint32 pFrame);
uint32 getSampleForTime(bigtime_t pTime);
uint32 getSampleForFrame(uint32 pFrame);
uint32 getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk);
uint64 getOffsetForChunk(uint32 pChunkID);
@@ -377,12 +433,15 @@ public:
uint32 getNoSamplesInChunk(uint32 pChunkID);
uint32 getTotalChunks();
float getSampleRate();
float getFrameRate();
bool IsSyncSample(uint32 pSampleNo);
bool IsSingleSampleSize();
bool IsActive();
uint32 getBytesPerSample();
TKHDAtom *getTKHDAtom();
MDHDAtom *getMDHDAtom();
private:
@@ -391,6 +450,7 @@ private:
uint32 framecount;
uint32 bytespersample;
uint32 timescale;
};
// Atom class for reading the media container atom
@@ -401,7 +461,7 @@ public:
void OnProcessMetaData();
char *OnGetAtomName();
uint32 getMediaComponentSubType();
uint32 getMediaHandlerType();
};
// Atom class for reading the media information atom
@@ -412,7 +472,7 @@ public:
void OnProcessMetaData();
char *OnGetAtomName();
uint32 getMediaComponentSubType();
uint32 getMediaHandlerType();
};
// Atom class for reading the stbl atom
@@ -423,7 +483,7 @@ public:
void OnProcessMetaData();
char *OnGetAtomName();
uint32 getMediaComponentSubType();
uint32 getMediaHandlerType();
};
// Atom class for reading the dinf atom
@@ -458,7 +518,7 @@ private:
};
// Atom class for reading the Media Handler atom
class HDLRAtom : public AtomBase {
class HDLRAtom : public FullAtom {
public:
HDLRAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~HDLRAtom();
@@ -467,26 +527,11 @@ public:
bool IsVideoHandler();
bool IsAudioHandler();
uint32 getMediaComponentSubType();
uint32 getMediaHandlerType();
private:
hdlr theHeader;
};
class FTYPAtom : public AtomBase {
public:
FTYPAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
virtual ~FTYPAtom();
void OnProcessMetaData();
char *OnGetAtomName();
bool HasBrand(uint32 brand);
private:
uint32 major_brand;
uint32 minor_version;
uint32 compatable_brands[32]; // Should be infinite but we will settle for max 32
uint32 total_brands;
char *name;
};
#endif
@@ -30,6 +30,7 @@ TRAKAtom::TRAKAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType,
theMDHDAtom = NULL;
framecount = 0;
bytespersample = 0;
timescale = 1;
}
TRAKAtom::~TRAKAtom()
@@ -78,16 +79,20 @@ bigtime_t TRAKAtom::Duration(uint32 TimeScale)
return getMDHDAtom()->getDuration();
}
return bigtime_t(getTKHDAtom()->getDuration() * 1000000L) / TimeScale;
return bigtime_t(getTKHDAtom()->getDuration() * 1000000.0) / TimeScale;
}
void TRAKAtom::OnChildProcessingComplete()
{
timescale = getMDHDAtom()->getTimeScale();
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(GetChildAtom(uint32('stts'),0));
if (aSTTSAtom) {
framecount = aSTTSAtom->getSUMCounts();
aSTTSAtom->setFrameRate(getFrameRate());
}
}
// Is this a video track
@@ -104,25 +109,46 @@ bool TRAKAtom::IsAudio()
return (GetChildAtom(uint32('smhd'),0) != NULL);
}
uint32 TRAKAtom::getTimeForFrame(uint32 pFrame, uint32 pTimeScale)
// frames per us
float TRAKAtom::getFrameRate()
{
AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
if (aAtomBase) {
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
if (IsAudio()) {
AtomBase *aAtomBase = GetChildAtom(uint32('stsd'),0);
if (aAtomBase) {
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
if (IsAudio()) {
// Frame * SampleRate = Time
} else if (IsVideo()) {
// Frame * fps = Time
return pFrame * ((aSTTSAtom->getSUMCounts() * 1000000L) / Duration(pTimeScale));
SoundDescriptionV1 aAudioDescription = aSTSDAtom->getAsAudio();
return (aAudioDescription.desc.SampleRate / 65536.0) / aAudioDescription.bytesPerFrame;
}
} else if (IsVideo()) {
return (framecount * 1000000.0) / Duration();
}
return 0.0;
}
float TRAKAtom::getSampleRate()
{
// Only valid for Audio
if (IsAudio()) {
AtomBase *aAtomBase = GetChildAtom(uint32('stsd'),0);
if (aAtomBase) {
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
SoundDescriptionV1 aAudioDescription = aSTSDAtom->getAsAudio();
return aAudioDescription.desc.SampleRate / 65536;
}
}
return 0;
return 0.0;
}
uint32 TRAKAtom::getSampleForTime(uint32 pTime)
bigtime_t TRAKAtom::getTimeForFrame(uint32 pFrame)
{
return bigtime_t((pFrame * 1000000.0) / getFrameRate());
}
uint32 TRAKAtom::getSampleForTime(bigtime_t pTime)
{
AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
@@ -138,7 +164,7 @@ uint32 TRAKAtom::getSampleForFrame(uint32 pFrame)
AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
if (aAtomBase) {
return (dynamic_cast<STTSAtom *>(aAtomBase))->getSampleForFrame(pFrame);
return (dynamic_cast<STTSAtom *>(aAtomBase))->getSampleForTime(getTimeForFrame(pFrame));
}
return 0;
@@ -140,6 +140,11 @@ struct TimeToSample {
uint32 Duration;
};
struct CompTimeToSample {
uint32 Count;
uint32 Offset;
};
struct SampleToChunk {
uint32 FirstChunk;
uint32 SamplesPerChunk;
@@ -34,7 +34,7 @@
#include "mov_reader.h"
//#define TRACE_MOV_READER
#define TRACE_MOV_READER
#ifdef TRACE_MOV_READER
#define TRACE printf
#else
@@ -56,7 +56,6 @@ struct mov_cookie
bool audio;
// audio only:
off_t byte_pos;
uint32 bytes_per_sec_rate;
uint32 bytes_per_sec_scale;
@@ -67,6 +66,7 @@ struct mov_cookie
uint32 frame_pos;
uint32 frames_per_sec_rate;
uint32 frames_per_sec_scale;
uint32 frame_size;
};
@@ -175,11 +175,12 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie)
codecID = B_BENDIAN_TO_HOST_INT32(audio_format->compression);
cookie->frame_count = theFileReader->getAudioFrameCount(cookie->stream);
// frame_count is actually sample_count for audio - makes media_player happy but david sad
cookie->frame_count = theFileReader->getFrameCount(cookie->stream) * audio_format->FrameSize;
cookie->duration = theFileReader->getAudioDuration(cookie->stream);
cookie->frame_size = audio_format->FrameSize;
cookie->audio = true;
cookie->byte_pos = 0;
if (stream_header->scale && stream_header->rate) {
cookie->bytes_per_sec_rate = stream_header->rate * audio_format->SampleSize * audio_format->NoOfChannels / 8;
@@ -211,6 +212,7 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie)
(audio_format->compression == AUDIO_RAW) ||
(audio_format->compression == AUDIO_TWOS1) ||
(audio_format->compression == AUDIO_TWOS2)) {
description.family = B_BEOS_FORMAT_FAMILY;
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
if (B_OK != formats.GetFormatFor(description, format)) {
@@ -350,7 +352,8 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie)
cookie->audio = false;
cookie->line_count = theFileReader->MovMainHeader()->height;
cookie->frame_size = 1;
if (stream_header->scale && stream_header->rate) {
cookie->frames_per_sec_rate = stream_header->rate;
cookie->frames_per_sec_scale = stream_header->scale;
@@ -475,14 +478,14 @@ movReader::Seek(void *cookie,
if (seekTo & B_MEDIA_SEEK_TO_TIME) {
// frame = (time * rate) / fps / 1000000LL
*frame = ((*time * movcookie->frames_per_sec_rate) / (int64)movcookie->frames_per_sec_scale) / 1000000LL;
movcookie->frame_pos = *frame;
movcookie->frame_pos = *frame / movcookie->frame_size;
TRACE("Time %Ld to Frame %Ld\n",*time, *frame);
}
if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
// time = frame * 1000000LL * fps / rate
*time = (*frame * 1000000LL * (int64)movcookie->frames_per_sec_scale) / movcookie->frames_per_sec_rate;
movcookie->frame_pos = *frame;
movcookie->frame_pos = *frame / movcookie->frame_size;
TRACE("Frame %Ld to Time %Ld\n", *frame, *time);
}
@@ -559,47 +562,53 @@ movReader::GetNextChunk(void *_cookie,
{
mov_cookie *cookie = (mov_cookie *)_cookie;
int64 start; uint32 size; bool keyframe;
int64 start;
uint32 size;
bool keyframe;
if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe))
if (!theFileReader->GetNextChunkInfo(cookie->stream, (cookie->frame_pos / cookie->frame_size), &start, &size, &keyframe)) {
TRACE("%s LAST BUFFER : %d (%ld)\n",cookie->audio ? "AUDIO" : "VIDEO", cookie->stream, cookie->frame_pos);
return B_LAST_BUFFER_ERROR;
}
if (cookie->buffer_size < size) {
delete [] cookie->buffer;
cookie->buffer_size = (size + 15) & ~15;
cookie->buffer = new char [cookie->buffer_size];
}
mediaHeader->start_time = bigtime_t(double(cookie->frame_pos) * 1000000.0 * double(cookie->frames_per_sec_scale)) / cookie->frames_per_sec_rate;
if (cookie->audio) {
TRACE("Audio stream %d: chunk %ld expected start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
TRACE("Audio");
mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
// This will only work with raw audio I think.
mediaHeader->start_time = (cookie->byte_pos * 1000000LL * cookie->bytes_per_sec_scale) / cookie->bytes_per_sec_rate;
TRACE("Audio - Frames in Chunk %ld / Actual Start Time %Ld using byte_pos\n",theFileReader->getNoFramesInChunk(cookie->stream,cookie->frame_pos),mediaHeader->start_time);
// We should find the current frame position (ie first frame in chunk) then compute using fps
cookie->frame_pos = theFileReader->getFirstFrameInChunk(cookie->stream,cookie->frame_pos);
mediaHeader->start_time = (cookie->frame_pos * 1000000LL * (int64)cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
TRACE("Audio - Frames in Chunk %ld / Actual Start Time %Ld using frame_no %ld\n",theFileReader->getNoFramesInChunk(cookie->stream,cookie->frame_pos),mediaHeader->start_time, cookie->frame_pos);
cookie->byte_pos += size;
} else {
TRACE("Video stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
mediaHeader->start_time = (cookie->frame_pos * 1000000LL * (int64)cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
TRACE("Video");
mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
mediaHeader->u.encoded_video.first_active_line = 0;
mediaHeader->u.encoded_video.line_count = cookie->line_count;
mediaHeader->u.encoded_video.field_number = 0;
mediaHeader->u.encoded_video.field_sequence = cookie->frame_pos;
}
cookie->frame_pos++;
TRACE("stream %d: start_time %.6f\n", cookie->stream, mediaHeader->start_time / 1000000.0);
TRACE(" stream %d: frame %ld start time %.6f file pos %lld Size %ld key frame %s\n",cookie->stream, (cookie->frame_pos / cookie->frame_size), mediaHeader->start_time / 1000000.0, start, size, keyframe ? "true" : "false");
cookie->frame_pos += cookie->frame_size;
*chunkBuffer = cookie->buffer;
*chunkSize = size;
return (int)size == theFileReader->Source()->ReadAt(start, cookie->buffer, size) ? B_OK : B_LAST_BUFFER_ERROR;
ssize_t bytesRead = theFileReader->Source()->ReadAt(start, cookie->buffer, size);
if (bytesRead < B_OK)
return bytesRead;
if (bytesRead < (ssize_t)size) {
ERROR("Not enough bytes read asked for %ld got %ld\n", size, bytesRead);
return B_LAST_BUFFER_ERROR;
}
return B_OK;
}
@@ -69,6 +69,7 @@ MP4FileReader::IsEndOfData(off_t pPosition)
if ((aAtomBase) && (aAtomBase->getAtomSize() > 8)) {
MDATAtom *aMDATAtom = dynamic_cast<MDATAtom *>(aAtomBase);
if (pPosition >= aMDATAtom->getAtomOffset() && pPosition <= aMDATAtom->getEOF()) {
// printf("IsEndOfData %Ld,%Ld,%Ld\n",pPosition,aMDATAtom->getAtomOffset(),aMDATAtom->getEOF());
return false;
}
}
@@ -634,7 +635,7 @@ MP4FileReader::GetNextChunkInfo(uint32 streamIndex, uint32 pFrameNo,
*keyframe = IsKeyFrame(streamIndex, pFrameNo);
}
// printf("start %Ld, size %ld, eof %s, eod %s\n",*start,*size, IsEndOfFile(*start + *size) ? "true" : "false", IsEndOfData(*start + *size) ? "true" : "false");
// printf("frame %ld start %Ld, size %ld, eof %s, eod %s\n",pFrameNo,*start,*size, IsEndOfFile(*start + *size) ? "true" : "false", IsEndOfData(*start + *size) ? "true" : "false");
// TODO need a better method for detecting End of Data Note ChunkSize of 0 seems to be it.
if (IsEndOfFile(*start + *size) || IsEndOfData(*start + *size)) {
@@ -31,7 +31,7 @@
#include "WavReaderPlugin.h"
#include "RawFormats.h"
//#define TRACE_WAVE_READER
#define TRACE_WAVE_READER
#ifdef TRACE_WAVE_READER
#define TRACE printf
#else
@@ -137,7 +137,11 @@ WavReader::Sniff(int32 *streamCount)
}
format_struct format;
wave_format_ex wav_format;
format_struct_extensible format_ext;
mpeg1_wav_format mpeg1_format;
mpeg3_wav_format mpeg3_format;
fact_struct fact;
// read all chunks and search for "fact", "fmt" (normal or extensible) and "data"
@@ -146,6 +150,9 @@ WavReader::Sniff(int32 *streamCount)
bool foundFmt = false;
bool foundFmtExt = false;
bool foundData = false;
bool foundMPEG1 = false;
bool foundMPEG3 = false;
while (pos + sizeof(chunk_struct) <= fFileSize) {
chunk_struct chunk;
if (sizeof(chunk) != Source()->ReadAt(pos, &chunk, sizeof(chunk))) {
@@ -159,12 +166,43 @@ WavReader::Sniff(int32 *streamCount)
}
switch (UINT32(chunk.fourcc)) {
case FOURCC('f','m','t',' '):
if (UINT32(chunk.len) >= sizeof(format)) {
// So what do we have a std format structure, a wav_format structure or a extended structure
if (UINT32(chunk.len) >= sizeof(wav_format)) {
// Read both format and wav format
if (sizeof(format) != Source()->ReadAt(pos, &format, sizeof(format))) {
ERROR("WavReader::Sniff: format chunk reading failed\n");
break;
}
if (sizeof(wav_format) != Source()->ReadAt(pos, &wav_format, sizeof(wav_format))) {
ERROR("WavReader::Sniff: format chunk reading failed\n");
break;
}
foundFmt = true;
if (UINT16(wav_format.extra_size) == 12) {
// MPEG3 WAV FORMAT Structure
if (sizeof(mpeg3_format) != Source()->ReadAt(pos, &mpeg3_format, sizeof(mpeg3_format))) {
ERROR("WavReader::Sniff: format chunk reading failed\n");
break;
}
foundMPEG3 = true;
}
if (UINT16(wav_format.extra_size) == 22) {
// MPEG1 WAV FORMAT Structure
if (sizeof(mpeg1_format) != Source()->ReadAt(pos, &mpeg1_format, sizeof(mpeg1_format))) {
ERROR("WavReader::Sniff: format chunk reading failed\n");
break;
}
foundMPEG1 = true;
}
} else if (UINT32(chunk.len) >= sizeof(format)) {
if (sizeof(format) != Source()->ReadAt(pos, &format, sizeof(format))) {
ERROR("WavReader::Sniff: format chunk reading failed\n");
break;
}
foundFmt = true;
if (UINT32(chunk.len) >= sizeof(format_ext) && UINT16(format.format_tag) == 0xfffe) {
if (sizeof(format_ext) != Source()->ReadAt(pos, &format_ext, sizeof(format_ext))) {
ERROR("WavReader::Sniff: format extensible chunk reading failed\n");
@@ -231,6 +269,28 @@ WavReader::Sniff(int32 *streamCount)
if (foundFact) {
TRACE(" sample_length %ld\n", UINT32(fact.sample_length));
}
if (foundMPEG1) {
TRACE(" layer %d\n", UINT16(mpeg1_format.head_layer));
TRACE(" bitrate %ld\n", UINT32(mpeg1_format.head_bitrate));
TRACE(" mode %d\n", UINT16(mpeg1_format.head_mode));
TRACE(" mode ext %d\n", UINT16(mpeg1_format.head_mode_ext));
TRACE(" emphisis %d\n", UINT16(mpeg1_format.head_emphasis));
TRACE(" flags %d\n", UINT16(mpeg1_format.head_flags));
TRACE(" pts low %ld\n", UINT32(mpeg1_format.pts_low));
TRACE(" pts high %ld\n", UINT32(mpeg1_format.pts_high));
}
if (foundMPEG3) {
TRACE(" id %d\n", UINT16(mpeg3_format.id));
TRACE(" flags %ld\n", UINT32(mpeg3_format.flags));
TRACE(" block size %d\n", UINT16(mpeg3_format.block_size));
TRACE(" frames per block %d\n", UINT16(mpeg3_format.frames_per_block));
TRACE(" codec delay %d\n", UINT16(mpeg3_format.codec_delay));
fBufferSize = mpeg3_format.block_size;
} else {
fBufferSize = BUFFER_SIZE;
}
fMetaData.extra_size = 0;
fMetaData.channels = UINT16(format.channels);
@@ -298,7 +358,7 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
data->position = 0;
data->datasize = fDataSize;
data->fps = fMetaData.samples_per_sec;
data->buffersize = (BUFFER_SIZE / fMetaData.block_align) * fMetaData.block_align;
data->buffersize = (fBufferSize / fMetaData.block_align) * fMetaData.block_align;
data->buffer = malloc(data->buffersize);
data->framecount = fFrameCount ? fFrameCount : (8 * fDataSize) / (fMetaData.channels * fMetaData.bits_per_sample);
data->raw = fMetaData.format_tag == 0x0001;
@@ -71,6 +71,7 @@ private:
int64 fFrameCount;
int32 fFrameRate;
uint16 fBufferSize;
};
+34 -1
View File
@@ -56,7 +56,40 @@ struct wave_format_ex {
uint16 block_align;
uint16 bits_per_sample;
uint16 extra_size;
} _PACKED;
};
struct mpeg3_wav_format {
uint16 format_tag;
uint16 channels;
uint32 samples_per_sec;
uint32 avg_bytes_per_sec;
uint16 block_align;
uint16 bits_per_sample;
uint16 extra_size;
uint16 id;
uint32 flags;
uint16 block_size;
uint16 frames_per_block;
uint16 codec_delay;
};
struct mpeg1_wav_format {
uint16 format_tag;
uint16 channels;
uint32 samples_per_sec;
uint32 avg_bytes_per_sec;
uint16 block_align;
uint16 bits_per_sample;
uint16 extra_size;
uint16 head_layer;
uint32 head_bitrate;
uint16 head_mode;
uint16 head_mode_ext;
uint16 head_emphasis;
uint16 head_flags;
uint32 pts_low;
uint32 pts_high;
};
struct format_struct_extensible
{