From 22245b2dce2d7a2739cb0fe3a48fbf8ae2e04129 Mon Sep 17 00:00:00 2001 From: David McPaul Date: Thu, 30 Apr 2009 10:23:13 +0000 Subject: [PATCH] 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 --- src/add-ons/media/plugins/Jamfile | 2 + src/add-ons/media/plugins/avcodec/Jamfile | 4 +- src/add-ons/media/plugins/avcodec/avcodec.cpp | 8 +- .../media/plugins/avcodec/codectbl.cpp | 1 + .../media/plugins/avcodec/gfx_conv_mmx.cpp | 38 ++ .../media/plugins/avcodec/gfx_conv_mmx.h | 2 - .../media/plugins/avcodec/gfx_util.cpp | 4 +- .../media/plugins/avcodec/libavcodec/Jamfile | 2 +- .../media/plugins/avcodec/libavcodec/config.h | 8 +- .../media/plugins/avcodec/libavcodec/h264.c | 12 + .../plugins/avcodec/libavcodec/x86/Jamfile | 2 +- .../avcodec/libavcodec/x86/dsputil_mmx.c | 54 +- .../media/plugins/avcodec/libavutil/Jamfile | 2 +- .../media/plugins/avcodec/libswscale/Jamfile | 2 +- .../plugins/mov_reader/libMOV/MOVAtom.cpp | 76 ++- .../media/plugins/mov_reader/libMOV/MOVAtom.h | 41 +- .../mov_reader/libMOV/MOVFileReader.cpp | 609 +++++++++--------- .../plugins/mov_reader/libMOV/MOVFileReader.h | 47 +- .../plugins/mov_reader/libMOV/MOVParser.cpp | 359 +++++++---- .../plugins/mov_reader/libMOV/MOVParser.h | 143 ++-- .../plugins/mov_reader/libMOV/MOVTrakAtom.cpp | 54 +- .../plugins/mov_reader/libMOV/QTStructs.h | 5 + .../media/plugins/mov_reader/mov_reader.cpp | 67 +- .../mp4_reader/libMP4/MP4FileReader.cpp | 3 +- .../plugins/wav_reader/WavReaderPlugin.cpp | 66 +- .../plugins/wav_reader/WavReaderPlugin.h | 1 + src/add-ons/media/plugins/wav_reader/wav.h | 35 +- 27 files changed, 1081 insertions(+), 566 deletions(-) create mode 100644 src/add-ons/media/plugins/avcodec/gfx_conv_mmx.cpp diff --git a/src/add-ons/media/plugins/Jamfile b/src/add-ons/media/plugins/Jamfile index 89e56dfd1f..05333e53a0 100644 --- a/src/add-ons/media/plugins/Jamfile +++ b/src/add-ons/media/plugins/Jamfile @@ -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 diff --git a/src/add-ons/media/plugins/avcodec/Jamfile b/src/add-ons/media/plugins/avcodec/Jamfile index c201001f3d..09f3507b90 100644 --- a/src/add-ons/media/plugins/avcodec/Jamfile +++ b/src/add-ons/media/plugins/avcodec/Jamfile @@ -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 diff --git a/src/add-ons/media/plugins/avcodec/avcodec.cpp b/src/add-ons/media/plugins/avcodec/avcodec.cpp index a5dcf412a1..f4843bdd49 100644 --- a/src/add-ons/media/plugins/avcodec/avcodec.cpp +++ b/src/add-ons/media/plugins/avcodec/avcodec.cpp @@ -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) diff --git a/src/add-ons/media/plugins/avcodec/codectbl.cpp b/src/add-ons/media/plugins/avcodec/codectbl.cpp index 294c201b47..9e35fd22e4 100644 --- a/src/add-ons/media/plugins/avcodec/codectbl.cpp +++ b/src/add-ons/media/plugins/avcodec/codectbl.cpp @@ -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"}, diff --git a/src/add-ons/media/plugins/avcodec/gfx_conv_mmx.cpp b/src/add-ons/media/plugins/avcodec/gfx_conv_mmx.cpp new file mode 100644 index 0000000000..293ca0f5a2 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/gfx_conv_mmx.cpp @@ -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); +} + diff --git a/src/add-ons/media/plugins/avcodec/gfx_conv_mmx.h b/src/add-ons/media/plugins/avcodec/gfx_conv_mmx.h index 79456e4a61..63ce5cff2c 100644 --- a/src/add-ons/media/plugins/avcodec/gfx_conv_mmx.h +++ b/src/add-ons/media/plugins/avcodec/gfx_conv_mmx.h @@ -5,8 +5,6 @@ #include #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); diff --git a/src/add-ons/media/plugins/avcodec/gfx_util.cpp b/src/add-ons/media/plugins/avcodec/gfx_util.cpp index 6af7bd0848..f20fefe763 100644 --- a/src/add-ons/media/plugins/avcodec/gfx_util.cpp +++ b/src/add-ons/media/plugins/avcodec/gfx_util.cpp @@ -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) diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/Jamfile b/src/add-ons/media/plugins/avcodec/libavcodec/Jamfile index 36cec0fc6a..996f8c1533 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/Jamfile +++ b/src/add-ons/media/plugins/avcodec/libavcodec/Jamfile @@ -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 ; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/config.h b/src/add-ons/media/plugins/avcodec/libavcodec/config.h index 87cda3940e..a4fbf94f52 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/config.h +++ b/src/add-ons/media/plugins/avcodec/libavcodec/config.h @@ -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 diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/h264.c b/src/add-ons/media/plugins/avcodec/libavcodec/h264.c index 91f20c9867..8788a6796c 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/h264.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/h264.c @@ -2412,6 +2412,8 @@ b= t; } } } +#include +#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); diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/x86/Jamfile b/src/add-ons/media/plugins/avcodec/libavcodec/x86/Jamfile index 7249eb0276..4365af8aa1 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/x86/Jamfile +++ b/src/add-ons/media/plugins/avcodec/libavcodec/x86/Jamfile @@ -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 ; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/x86/dsputil_mmx.c b/src/add-ons/media/plugins/avcodec/libavcodec/x86/dsputil_mmx.c index 2e6563c1d3..bef0d34eca 100644 --- a/src/add-ons/media/plugins/avcodec/libavcodec/x86/dsputil_mmx.c +++ b/src/add-ons/media/plugins/avcodec/libavcodec/x86/dsputil_mmx.c @@ -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 +#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 diff --git a/src/add-ons/media/plugins/avcodec/libavutil/Jamfile b/src/add-ons/media/plugins/avcodec/libavutil/Jamfile index 926d6955dd..a55b8f38c7 100644 --- a/src/add-ons/media/plugins/avcodec/libavutil/Jamfile +++ b/src/add-ons/media/plugins/avcodec/libavutil/Jamfile @@ -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 : diff --git a/src/add-ons/media/plugins/avcodec/libswscale/Jamfile b/src/add-ons/media/plugins/avcodec/libswscale/Jamfile index 83139ea67d..3c57a4411e 100644 --- a/src/add-ons/media/plugins/avcodec/libswscale/Jamfile +++ b/src/add-ons/media/plugins/avcodec/libswscale/Jamfile @@ -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 = ; diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.cpp index 2d859aa4d3..a5df061dad 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.cpp @@ -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++) { diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h index 7ed170a8db..4aea36632d 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h @@ -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 */ diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp index 72d6bca455..a7422c3c21 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp @@ -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(aAtomBase); - return pPosition >= aMdatAtom->getEOF(); + // check all mdat atoms to make sure position is within one of them + + for (uint32 index=0;indexgetAtomSize() > 8)) { + MDATAtom *aMDATAtom = dynamic_cast(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;iIsType(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(aAtomBase)->IsVideo())) { - return (dynamic_cast(aAtomBase)->Duration(1)); - } - - return 0; -} - -bigtime_t MOVFileReader::getAudioDuration(uint32 stream_index) -{ -AtomBase *aAtomBase; - - aAtomBase = GetChildAtom(uint32('trak'),stream_index); - - if ((aAtomBase) && (dynamic_cast(aAtomBase)->IsAudio())) { - return (dynamic_cast(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(aAtomBase)->IsActive())) { - if (dynamic_cast(aAtomBase)->IsAudio()) { - audio_index = int32(i); - } - if (dynamic_cast(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(aAtomBase)->IsVideo())) { - - return dynamic_cast(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(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(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(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(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(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;streamgetTimeScale(); +} + +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(aAtomBase)->IsVideo()) + return dynamic_cast(aAtomBase)->Duration(1); + + return 0; +} + +bigtime_t +MOVFileReader::getAudioDuration(uint32 streamIndex) +{ + AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex); + + if (aAtomBase && dynamic_cast(aAtomBase)->IsAudio()) + return dynamic_cast(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(aAtomBase)->IsActive())) { + if (dynamic_cast(aAtomBase)->IsAudio()) { + audioIndex = int32(i); + } + if (dynamic_cast(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(aAtomBase)->FrameCount(); + } + + return 1; +} + +uint32 +MOVFileReader::getAudioChunkCount(uint32 streamIndex) +{ + AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex); + + if (aAtomBase && dynamic_cast(aAtomBase)->IsAudio()) + return dynamic_cast(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(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(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(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(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(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(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(aAtomBase); - + aAtomBase = aTrakAtom->GetChildAtom(uint32('stsd'),0); - if (aAtomBase) { STSDAtom *aSTSDAtom = dynamic_cast(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(aAtomBase); - TRAKAtom *aTrakAtom = dynamic_cast(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(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(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(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(aAtom)->HasBrand(uint32('qt ')); diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h index 7c9eed4372..5acb936bc5 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h @@ -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 diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp index 7a40593308..2b206f5c4d 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp @@ -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;iDuration * 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;iDuration * 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;iCount); + 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;iTotalPrevSamples = 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;iSyncSampleNo); + 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;iEntrySize); - 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;iEntrySize = (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(getParent())->getMediaComponentSubType(); + return dynamic_cast(getParent())->getMediaHandlerType(); } void STSDAtom::ReadSoundDescription() @@ -945,6 +1089,9 @@ void STSDAtom::ReadVideoDescription() void STSDAtom::OnProcessMetaData() { + + FullAtom::OnProcessMetaData(); + ReadArrayHeader(&theHeader); for (uint32 i=0;i(getParent())->getMediaComponentSubType(); + return dynamic_cast(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(getParent())->getMediaComponentSubType(); + return dynamic_cast(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(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() diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h index 82fd9eac08..53f595171a 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h @@ -26,8 +26,6 @@ #define _MOV_PARSER_H -#include "MOVAtom.h" - #include #include #include @@ -35,7 +33,10 @@ #include +#include "MOVAtom.h" +typedef CompTimeToSample* CompTimeToSamplePtr; +typedef std::map > CompTimeToSampleArray; typedef SoundDescriptionV1* SoundDescPtr; typedef std::map > SoundDescArray; typedef VideoDescriptionV0* VideoDescPtr; @@ -48,11 +49,11 @@ typedef ChunkToOffset* ChunkToOffsetPtr; typedef std::map > ChunkToOffsetArray; typedef SyncSample* SyncSamplePtr; typedef std::map > SyncSampleArray; -typedef SampleSizeEntry* SampleSizeEntryPtr; -typedef std::map > SampleSizeArray; +typedef SampleSizeEntry* SampleSizePtr; +typedef std::map > 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 diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp index 67bdce5fac..44123664d7 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp @@ -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(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(aAtomBase); + if (IsAudio()) { + AtomBase *aAtomBase = GetChildAtom(uint32('stsd'),0); + if (aAtomBase) { + STSDAtom *aSTSDAtom = dynamic_cast(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(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(aAtomBase))->getSampleForFrame(pFrame); + return (dynamic_cast(aAtomBase))->getSampleForTime(getTimeForFrame(pFrame)); } return 0; diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/QTStructs.h b/src/add-ons/media/plugins/mov_reader/libMOV/QTStructs.h index 56b0eea228..88a8a5486d 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/QTStructs.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/QTStructs.h @@ -140,6 +140,11 @@ struct TimeToSample { uint32 Duration; }; +struct CompTimeToSample { + uint32 Count; + uint32 Offset; +}; + struct SampleToChunk { uint32 FirstChunk; uint32 SamplesPerChunk; diff --git a/src/add-ons/media/plugins/mov_reader/mov_reader.cpp b/src/add-ons/media/plugins/mov_reader/mov_reader.cpp index 691d7c8fa3..56adf0cfb0 100644 --- a/src/add-ons/media/plugins/mov_reader/mov_reader.cpp +++ b/src/add-ons/media/plugins/mov_reader/mov_reader.cpp @@ -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; } diff --git a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp index c74569f457..0fb7f96359 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp @@ -69,6 +69,7 @@ MP4FileReader::IsEndOfData(off_t pPosition) if ((aAtomBase) && (aAtomBase->getAtomSize() > 8)) { MDATAtom *aMDATAtom = dynamic_cast(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)) { diff --git a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp index 1acbcc9e51..14e08aa917 100644 --- a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp +++ b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp @@ -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; diff --git a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h index 6de7cd42b6..0152cf3793 100644 --- a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h +++ b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h @@ -71,6 +71,7 @@ private: int64 fFrameCount; int32 fFrameRate; + uint16 fBufferSize; }; diff --git a/src/add-ons/media/plugins/wav_reader/wav.h b/src/add-ons/media/plugins/wav_reader/wav.h index 28b75db802..a7dcdbac2a 100644 --- a/src/add-ons/media/plugins/wav_reader/wav.h +++ b/src/add-ons/media/plugins/wav_reader/wav.h @@ -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 {