* GCC 4 build fixes

* Some minor cleanup towards our style guide, but this could need
  much more work.
* Better error reporting in GetNextChunk() in case of an read error.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17541 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-05-22 18:08:13 +00:00
parent 3ad603ace4
commit 42c1d42429
6 changed files with 273 additions and 195 deletions
@@ -27,8 +27,8 @@
#include <SupportDefs.h> #include <SupportDefs.h>
// Std Headers #include <map>
#include <map.h>
struct ChunkIndex { struct ChunkIndex {
uint32 stream; uint32 stream;
@@ -25,15 +25,15 @@
#ifndef _MP4_ATOM_H #ifndef _MP4_ATOM_H
#define _MP4_ATOM_H #define _MP4_ATOM_H
#include "MP4Structs.h"
#include <File.h> #include <File.h>
#include <MediaDefs.h> #include <MediaDefs.h>
#include <MediaFormats.h> #include <MediaFormats.h>
#include <SupportDefs.h> #include <SupportDefs.h>
// Std Headers #include <map>
#include <map.h>
#include "MP4Structs.h"
/* /*
AtomBase AtomBase
@@ -22,16 +22,20 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <iostream.h>
#include <DataIO.h>
#include <SupportKit.h>
#include "MP4Parser.h" #include "MP4Parser.h"
#include "MP4FileReader.h" #include "MP4FileReader.h"
#include <DataIO.h>
#include <SupportKit.h>
#include <iostream>
extern AtomBase *getAtom(BPositionIO *pStream); extern AtomBase *getAtom(BPositionIO *pStream);
MP4FileReader::MP4FileReader(BPositionIO *pStream) MP4FileReader::MP4FileReader(BPositionIO *pStream)
{ {
theStream = pStream; theStream = pStream;
@@ -45,15 +49,18 @@ MP4FileReader::MP4FileReader(BPositionIO *pStream)
theMVHDAtom = NULL; theMVHDAtom = NULL;
} }
MP4FileReader::~MP4FileReader() MP4FileReader::~MP4FileReader()
{ {
theStream = NULL; theStream = NULL;
theMVHDAtom = NULL; theMVHDAtom = NULL;
} }
bool MP4FileReader::IsEndOfData(off_t pPosition)
bool
MP4FileReader::IsEndOfData(off_t pPosition)
{ {
AtomBase *aAtomBase; AtomBase* aAtomBase;
for (uint32 index=0;index<CountChildAtoms('mdat');index++) { for (uint32 index=0;index<CountChildAtoms('mdat');index++) {
aAtomBase = GetChildAtom(uint32('mdat'),index); aAtomBase = GetChildAtom(uint32('mdat'),index);
@@ -66,28 +73,36 @@ AtomBase *aAtomBase;
return true; return true;
} }
bool MP4FileReader::IsEndOfFile(off_t pPosition)
bool
MP4FileReader::IsEndOfFile(off_t position)
{ {
return (pPosition >= StreamSize); return (position >= StreamSize);
} }
bool MP4FileReader::IsEndOfFile()
bool
MP4FileReader::IsEndOfFile()
{ {
return (theStream->Position() >= StreamSize); return theStream->Position() >= StreamSize;
} }
bool MP4FileReader::AddChild(AtomBase *pChildAtom)
bool
MP4FileReader::AddChild(AtomBase *childAtom)
{ {
if (pChildAtom) { if (childAtom) {
atomChildren[TotalChildren++] = pChildAtom; atomChildren[TotalChildren++] = childAtom;
return true; return true;
} }
return false; return false;
} }
AtomBase *MP4FileReader::GetChildAtom(uint32 patomType, uint32 offset)
AtomBase *
MP4FileReader::GetChildAtom(uint32 patomType, uint32 offset)
{ {
for (uint32 i=0;i<TotalChildren;i++) { for (uint32 i = 0; i < TotalChildren; i++) {
if (atomChildren[i]->IsType(patomType)) { if (atomChildren[i]->IsType(patomType)) {
// found match, skip if offset non zero. // found match, skip if offset non zero.
if (offset == 0) { if (offset == 0) {
@@ -110,7 +125,9 @@ AtomBase *MP4FileReader::GetChildAtom(uint32 patomType, uint32 offset)
return NULL; return NULL;
} }
uint32 MP4FileReader::CountChildAtoms(uint32 patomType)
uint32
MP4FileReader::CountChildAtoms(uint32 patomType)
{ {
uint32 count = 0; uint32 count = 0;
@@ -120,9 +137,11 @@ uint32 MP4FileReader::CountChildAtoms(uint32 patomType)
return count; return count;
} }
MVHDAtom *MP4FileReader::getMVHDAtom()
MVHDAtom*
MP4FileReader::getMVHDAtom()
{ {
AtomBase *aAtomBase; AtomBase *aAtomBase;
if (theMVHDAtom == NULL) { if (theMVHDAtom == NULL) {
aAtomBase = GetChildAtom(uint32('mvhd')); aAtomBase = GetChildAtom(uint32('mvhd'));
@@ -133,9 +152,11 @@ AtomBase *aAtomBase;
return theMVHDAtom; return theMVHDAtom;
} }
void MP4FileReader::BuildSuperIndex()
void
MP4FileReader::BuildSuperIndex()
{ {
AtomBase *aAtomBase; AtomBase *aAtomBase;
for (uint32 stream=0;stream<getStreamCount();stream++) { for (uint32 stream=0;stream<getStreamCount();stream++) {
aAtomBase = GetChildAtom(uint32('trak'),stream); aAtomBase = GetChildAtom(uint32('trak'),stream);
@@ -155,137 +176,148 @@ AtomBase *aAtomBase;
} }
} }
uint32 MP4FileReader::getMovieTimeScale()
uint32
MP4FileReader::getMovieTimeScale()
{ {
return getMVHDAtom()->getTimeScale(); return getMVHDAtom()->getTimeScale();
} }
bigtime_t MP4FileReader::getMovieDuration()
bigtime_t
MP4FileReader::getMovieDuration()
{ {
return ((bigtime_t(getMVHDAtom()->getDuration()) * 1000000L) / getMovieTimeScale()); return (bigtime_t(getMVHDAtom()->getDuration()) * 1000000L)
/ getMovieTimeScale();
} }
uint32 MP4FileReader::getStreamCount()
uint32
MP4FileReader::getStreamCount()
{ {
// count the number of tracks in the file // count the number of tracks in the file
return (CountChildAtoms(uint32('trak'))); return CountChildAtoms(uint32('trak'));
} }
bigtime_t MP4FileReader::getVideoDuration(uint32 stream_index)
bigtime_t
MP4FileReader::getVideoDuration(uint32 streamIndex)
{ {
AtomBase *aAtomBase; AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
aAtomBase = GetChildAtom(uint32('trak'),stream_index); if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())
return dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
}
return 0; return 0;
} }
bigtime_t MP4FileReader::getAudioDuration(uint32 stream_index)
bigtime_t
MP4FileReader::getAudioDuration(uint32 streamIndex)
{ {
AtomBase *aAtomBase; AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
aAtomBase = GetChildAtom(uint32('trak'),stream_index); if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())
return dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())) {
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
}
return 0; return 0;
} }
bigtime_t MP4FileReader::getMaxDuration()
bigtime_t
MP4FileReader::getMaxDuration()
{ {
AtomBase *aAtomBase; AtomBase *aAtomBase;
int32 video_index,audio_index; int32 videoIndex = -1;
video_index = -1; int32 audioIndex = -1;
audio_index = -1;
// find the active video and audio tracks // find the active video and audio tracks
for (uint32 i=0;i<getStreamCount();i++) { for (uint32 i = 0; i < getStreamCount(); i++) {
aAtomBase = GetChildAtom(uint32('trak'),i); aAtomBase = GetChildAtom(uint32('trak'), i);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsActive())) { if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsActive())) {
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio()) { if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio()) {
audio_index = int32(i); audioIndex = int32(i);
} }
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo()) { if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo()) {
video_index = int32(i); videoIndex = int32(i);
} }
} }
} }
if ((video_index >= 0) && (audio_index >= 0)) { if (videoIndex >= 0 && audioIndex >= 0) {
return MAX(getVideoDuration(video_index),getAudioDuration(audio_index)); return max_c(getVideoDuration(videoIndex),
getAudioDuration(audioIndex));
} }
if ((video_index < 0) && (audio_index >= 0)) { if (videoIndex < 0 && audioIndex >= 0) {
return getAudioDuration(audio_index); return getAudioDuration(audioIndex);
} }
if ((video_index >= 0) && (audio_index < 0)) { if (videoIndex >= 0 && audioIndex < 0) {
return getVideoDuration(video_index); return getVideoDuration(videoIndex);
} }
return 0; return 0;
} }
uint32 MP4FileReader::getVideoFrameCount(uint32 stream_index)
uint32
MP4FileReader::getVideoFrameCount(uint32 streamIndex)
{ {
AtomBase *aAtomBase; AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount(); return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
}
return 1; return 1;
} }
uint32 MP4FileReader::getAudioFrameCount(uint32 stream_index)
uint32
MP4FileReader::getAudioFrameCount(uint32 streamIndex)
{ {
if (IsAudio(stream_index)) { if (IsAudio(streamIndex)) {
return uint32(((getAudioDuration(stream_index) * AudioFormat(stream_index)->SampleRate) / 1000000L) + 0.5); return uint32(((getAudioDuration(streamIndex)
* AudioFormat(streamIndex)->SampleRate) / 1000000L) + 0.5);
} }
return 0; return 0;
} }
bool MP4FileReader::IsVideo(uint32 stream_index)
bool
MP4FileReader::IsVideo(uint32 streamIndex)
{ {
// Look for a trak with a vmhd atom // Look for a 'trak' with a vmhd atom
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase)
return dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo();
if (aAtomBase) { // No track
return (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo());
}
// No trak
return false; return false;
} }
bool MP4FileReader::IsAudio(uint32 stream_index)
bool
MP4FileReader::IsAudio(uint32 streamIndex)
{ {
// Look for a trak with a smhd atom // Look for a 'trak' with a smhd atom
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase) { if (aAtomBase)
return (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio()); return dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio();
}
// No trak // No track
return false; return false;
} }
uint32 MP4FileReader::getFirstFrameInChunk(uint32 stream_index, uint32 pChunkID)
uint32
MP4FileReader::getFirstFrameInChunk(uint32 streamIndex, uint32 pChunkID)
{ {
// Find Track // Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
if (aAtomBase) { if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase); TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
@@ -295,7 +327,9 @@ uint32 MP4FileReader::getFirstFrameInChunk(uint32 stream_index, uint32 pChunkID)
return 0; return 0;
} }
uint32 MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
uint32
MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
{ {
// Find Track // Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
@@ -303,9 +337,8 @@ uint32 MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase); TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
uint32 ChunkNo = 1; uint32 ChunkNo = 1;
if (IsAudio(stream_index)) { if (IsAudio(stream_index))
ChunkNo = pFrameNo; ChunkNo = pFrameNo;
}
if (IsVideo(stream_index)) { if (IsVideo(stream_index)) {
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
@@ -320,7 +353,9 @@ uint32 MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
return 0; return 0;
} }
uint64 MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
uint64
MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
{ {
// Find Track // Find Track
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
@@ -336,7 +371,6 @@ uint64 MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
} }
if (IsVideo(stream_index)) { if (IsVideo(stream_index)) {
if (pFrameNo < aTrakAtom->FrameCount()) { if (pFrameNo < aTrakAtom->FrameCount()) {
// Get Sample for Frame // Get Sample for Frame
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
@@ -369,7 +403,9 @@ uint64 MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
return 0; return 0;
} }
status_t MP4FileReader::ParseFile()
status_t
MP4FileReader::ParseFile()
{ {
AtomBase *aChild; AtomBase *aChild;
while (IsEndOfFile() == false) { while (IsEndOfFile() == false) {
@@ -389,7 +425,9 @@ status_t MP4FileReader::ParseFile()
return B_OK; return B_OK;
} }
const mp4_main_header *MP4FileReader::MovMainHeader()
const mp4_main_header*
MP4FileReader::MovMainHeader()
{ {
// Fill In theMainHeader // Fill In theMainHeader
// uint32 micro_sec_per_frame; // uint32 micro_sec_per_frame;
@@ -409,10 +447,10 @@ const mp4_main_header *MP4FileReader::MovMainHeader()
theMainHeader.flags = 0; theMainHeader.flags = 0;
theMainHeader.initial_frames = 0; theMainHeader.initial_frames = 0;
while ( videoStream < theMainHeader.streams ) { while (videoStream < theMainHeader.streams) {
if (IsVideo(videoStream) && IsActive(videoStream)) { if (IsVideo(videoStream) && IsActive(videoStream))
break; break;
}
videoStream++; videoStream++;
} }
@@ -436,10 +474,11 @@ const mp4_main_header *MP4FileReader::MovMainHeader()
return &theMainHeader; return &theMainHeader;
} }
const AudioMetaData *MP4FileReader::AudioFormat(uint32 stream_index, size_t *size = 0)
const AudioMetaData *
MP4FileReader::AudioFormat(uint32 stream_index, size_t *size)
{ {
if (IsAudio(stream_index)) { if (IsAudio(stream_index)) {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) { if (aAtomBase) {
@@ -470,20 +509,19 @@ const AudioMetaData *MP4FileReader::AudioFormat(uint32 stream_index, size_t *
return NULL; return NULL;
} }
const VideoMetaData *MP4FileReader::VideoFormat(uint32 stream_index)
const VideoMetaData*
MP4FileReader::VideoFormat(uint32 stream_index)
{ {
if (IsVideo(stream_index)) { if (IsVideo(stream_index)) {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) { if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase); TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
aAtomBase = aTrakAtom->GetChildAtom(uint32('stsd'),0); aAtomBase = aTrakAtom->GetChildAtom(uint32('stsd'),0);
if (aAtomBase) { if (aAtomBase) {
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase); STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
VideoDescription aVideoDescription = aSTSDAtom->getAsVideo(); VideoDescription aVideoDescription = aSTSDAtom->getAsVideo();
theVideo.compression = aVideoDescription.codecid; theVideo.compression = aVideoDescription.codecid;
@@ -516,7 +554,9 @@ const VideoMetaData *MP4FileReader::VideoFormat(uint32 stream_index)
return NULL; return NULL;
} }
const mp4_stream_header *MP4FileReader::StreamFormat(uint32 stream_index)
const mp4_stream_header*
MP4FileReader::StreamFormat(uint32 stream_index)
{ {
// Fill In a Stream Header // Fill In a Stream Header
theStreamHeader.length = 0; theStreamHeader.length = 0;
@@ -542,14 +582,15 @@ const mp4_stream_header *MP4FileReader::StreamFormat(uint32 stream_index)
return &theStreamHeader; return &theStreamHeader;
} }
uint32 MP4FileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo)
uint32
MP4FileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo)
{ {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) { if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase); TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
if (IsAudio(stream_index)) { if (IsAudio(stream_index)) {
// We read audio in chunk by chunk so chunk size is chunk size // We read audio in chunk by chunk so chunk size is chunk size
uint32 ChunkNo = pFrameNo; uint32 ChunkNo = pFrameNo;
off_t Chunk_Start = aTrakAtom->getOffsetForChunk(ChunkNo); off_t Chunk_Start = aTrakAtom->getOffsetForChunk(ChunkNo);
@@ -565,13 +606,14 @@ uint32 MP4FileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo)
return aTrakAtom->getSizeForSample(SampleNo); return aTrakAtom->getSizeForSample(SampleNo);
} }
} }
} }
return 0; return 0;
} }
bool MP4FileReader::IsKeyFrame(uint32 stream_index, uint32 pFrameNo)
bool
MP4FileReader::IsKeyFrame(uint32 stream_index, uint32 pFrameNo)
{ {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) { if (aAtomBase) {
@@ -584,7 +626,10 @@ bool MP4FileReader::IsKeyFrame(uint32 stream_index, uint32 pFrameNo)
return false; return false;
} }
bool MP4FileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t *start, uint32 *size, bool *keyframe)
bool
MP4FileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo,
off_t *start, uint32 *size, bool *keyframe)
{ {
*start = getOffsetForFrame(stream_index, pFrameNo); *start = getOffsetForFrame(stream_index, pFrameNo);
*size = getChunkSize(stream_index, pFrameNo); *size = getChunkSize(stream_index, pFrameNo);
@@ -594,10 +639,13 @@ bool MP4FileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t
} }
// TODO need a better method for detecting End of Data Note ChunkSize of 0 seems to be it. // 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))); return *start > 0 && *size > 0 && !IsEndOfFile(*start + *size)
&& !IsEndOfData(*start + *size);
} }
bool MP4FileReader::IsActive(uint32 stream_index)
bool
MP4FileReader::IsActive(uint32 stream_index)
{ {
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
if (aAtomBase) { if (aAtomBase) {
@@ -608,14 +656,14 @@ bool MP4FileReader::IsActive(uint32 stream_index)
return false; return false;
} }
/* static */
bool MP4FileReader::IsSupported(BPositionIO *source)
{
AtomBase *aAtom;
aAtom = getAtom(source); /* static */
if (aAtom) { bool
return (aAtom->IsKnown()); MP4FileReader::IsSupported(BPositionIO *source)
} {
AtomBase *aAtom = getAtom(source);
if (aAtom)
return aAtom->IsKnown();
return false; return false;
} }
@@ -31,7 +31,7 @@
#include <SupportDefs.h> #include <SupportDefs.h>
// Std Headers // Std Headers
#include <map.h> #include <map>
#include "MP4Atom.h" #include "MP4Atom.h"
@@ -22,6 +22,12 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef MP4_STRUCTS_H
#define MP4_STRUCTS_H
#include <SupportDefs.h>
#define AUDIO_NONE 'NONE' #define AUDIO_NONE 'NONE'
#define AUDIO_RAW 'raw ' #define AUDIO_RAW 'raw '
@@ -33,8 +39,7 @@
#define AUDIO_MPEG3_CBR 0x6D730055 #define AUDIO_MPEG3_CBR 0x6D730055
// this is all from the avi reader. we rework it for mp4 // this is all from the avi reader. we rework it for mp4
struct mp4_main_header struct mp4_main_header {
{
uint32 micro_sec_per_frame; uint32 micro_sec_per_frame;
uint32 max_bytes_per_sec; uint32 max_bytes_per_sec;
uint32 padding_granularity; uint32 padding_granularity;
@@ -273,3 +278,5 @@ struct VideoDescription {
uint8 *theVOL; uint8 *theVOL;
size_t VOLSize; size_t VOLSize;
}; };
#endif // MP4_STRUCTS_H
@@ -22,29 +22,33 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <DataIO.h>
#include <StopWatch.h>
#include <ByteOrder.h>
#include <InterfaceDefs.h>
#include <MediaFormats.h>
#include "RawFormats.h"
#include "mp4_reader.h" #include "mp4_reader.h"
#include "RawFormats.h"
#include <ByteOrder.h>
#include <DataIO.h>
#include <InterfaceDefs.h>
#include <MediaFormats.h>
#include <StopWatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRACE_MP4_READER #define TRACE_MP4_READER
#ifdef TRACE_MP4_READER #ifdef TRACE_MP4_READER
#define TRACE printf # define TRACE printf
#else #else
#define TRACE(a...) # define TRACE(a...)
#endif #endif
#define ERROR(a...) fprintf(stderr, a) #define ERROR(a...) fprintf(stderr, a)
struct mp4_cookie
{ struct mp4_cookie {
unsigned stream; unsigned stream;
char * buffer; char * buffer;
unsigned buffer_size; unsigned buffer_size;
@@ -77,17 +81,20 @@ mp4Reader::mp4Reader()
TRACE("mp4Reader::mp4Reader\n"); TRACE("mp4Reader::mp4Reader\n");
} }
mp4Reader::~mp4Reader() mp4Reader::~mp4Reader()
{ {
delete theFileReader; delete theFileReader;
} }
const char * const char *
mp4Reader::Copyright() mp4Reader::Copyright()
{ {
return "MPEG4 & libMP4, " B_UTF8_COPYRIGHT " by David McPaul"; return "MPEG4 & libMP4, " B_UTF8_COPYRIGHT " by David McPaul";
} }
status_t status_t
mp4Reader::Sniff(int32 *streamCount) mp4Reader::Sniff(int32 *streamCount)
{ {
@@ -118,6 +125,7 @@ mp4Reader::Sniff(int32 *streamCount)
return B_OK; return B_OK;
} }
void void
mp4Reader::GetFileFormatInfo(media_file_format *mff) mp4Reader::GetFileFormatInfo(media_file_format *mff)
{ {
@@ -133,6 +141,7 @@ mp4Reader::GetFileFormatInfo(media_file_format *mff)
strcpy(mff->pretty_name, "MPEG-4 (MP4) file format"); strcpy(mff->pretty_name, "MPEG-4 (MP4) file format");
} }
status_t status_t
mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie) mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
{ {
@@ -180,40 +189,46 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
cookie->chunk_pos = 1; cookie->chunk_pos = 1;
if (stream_header->scale && stream_header->rate) { if (stream_header->scale && stream_header->rate) {
cookie->bytes_per_sec_rate = stream_header->rate * audio_format->SampleSize * audio_format->NoOfChannels / 8; cookie->bytes_per_sec_rate = stream_header->rate *
audio_format->SampleSize * audio_format->NoOfChannels / 8;
cookie->bytes_per_sec_scale = stream_header->scale; cookie->bytes_per_sec_scale = stream_header->scale;
cookie->frames_per_sec_rate = stream_header->rate; cookie->frames_per_sec_rate = stream_header->rate;
cookie->frames_per_sec_scale = stream_header->scale; cookie->frames_per_sec_scale = stream_header->scale;
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using both)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale); TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using both)\n",
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
} else if (stream_header->rate) { } else if (stream_header->rate) {
cookie->bytes_per_sec_rate = stream_header->rate * audio_format->SampleSize * audio_format->NoOfChannels / 8; cookie->bytes_per_sec_rate = stream_header->rate * audio_format->SampleSize
* audio_format->NoOfChannels / 8;
cookie->bytes_per_sec_scale = 1; cookie->bytes_per_sec_scale = 1;
cookie->frames_per_sec_rate = stream_header->rate; cookie->frames_per_sec_rate = stream_header->rate;
cookie->frames_per_sec_scale = 1; cookie->frames_per_sec_scale = 1;
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using rate)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale); TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using rate)\n",
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
} else if (audio_format->PacketSize) { } else if (audio_format->PacketSize) {
cookie->bytes_per_sec_rate = audio_format->PacketSize; cookie->bytes_per_sec_rate = audio_format->PacketSize;
cookie->bytes_per_sec_scale = 1; cookie->bytes_per_sec_scale = 1;
cookie->frames_per_sec_rate = audio_format->PacketSize * 8 / audio_format->SampleSize / audio_format->NoOfChannels; cookie->frames_per_sec_rate = audio_format->PacketSize * 8
/ audio_format->SampleSize / audio_format->NoOfChannels;
cookie->frames_per_sec_scale = 1; cookie->frames_per_sec_scale = 1;
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using PacketSize)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale); TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using PacketSize)\n",
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
} else { } else {
cookie->bytes_per_sec_rate = 128000; cookie->bytes_per_sec_rate = 128000;
cookie->bytes_per_sec_scale = 8; cookie->bytes_per_sec_scale = 8;
cookie->frames_per_sec_rate = 16000; cookie->frames_per_sec_rate = 16000;
cookie->frames_per_sec_scale = 1; cookie->frames_per_sec_scale = 1;
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using fallback)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale); TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using fallback)\n",
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
} }
if ((audio_format->compression == AUDIO_NONE) || if (audio_format->compression == AUDIO_NONE
(audio_format->compression == AUDIO_RAW) || || audio_format->compression == AUDIO_RAW
(audio_format->compression == AUDIO_TWOS1) || || audio_format->compression == AUDIO_TWOS1
(audio_format->compression == AUDIO_TWOS2)) { || audio_format->compression == AUDIO_TWOS2) {
description.family = B_BEOS_FORMAT_FAMILY; description.family = B_BEOS_FORMAT_FAMILY;
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO; description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
if (B_OK != formats.GetFormatFor(description, format)) { if (B_OK != formats.GetFormatFor(description, format))
format->type = B_MEDIA_RAW_AUDIO; format->type = B_MEDIA_RAW_AUDIO;
}
format->u.raw_audio.frame_rate = cookie->frames_per_sec_rate / cookie->frames_per_sec_scale; format->u.raw_audio.frame_rate = cookie->frames_per_sec_rate / cookie->frames_per_sec_scale;
format->u.raw_audio.channel_count = audio_format->NoOfChannels; format->u.raw_audio.channel_count = audio_format->NoOfChannels;
@@ -477,9 +492,7 @@ mp4Reader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
status_t status_t
mp4Reader::Seek(void *cookie, mp4Reader::Seek(void *cookie, uint32 seekTo, int64 *frame, bigtime_t *time)
uint32 seekTo,
int64 *frame, bigtime_t *time)
{ {
// We should seek to nearest keyframe requested // We should seek to nearest keyframe requested
@@ -515,21 +528,23 @@ mp4Reader::Seek(void *cookie,
status_t status_t
mp4Reader::GetNextChunk(void *_cookie, mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
const void **chunkBuffer, size_t *chunkSize, size_t *chunkSize, media_header *mediaHeader)
media_header *mediaHeader)
{ {
mp4_cookie *cookie = (mp4_cookie *)_cookie; mp4_cookie *cookie = (mp4_cookie *)_cookie;
int64 start;
int64 start; uint32 size; bool keyframe; uint32 size;
bool keyframe;
if (cookie->audio) { if (cookie->audio) {
// use chunk position // use chunk position
if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->chunk_pos, &start, &size, &keyframe)) if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->chunk_pos,
&start, &size, &keyframe))
return B_LAST_BUFFER_ERROR; return B_LAST_BUFFER_ERROR;
} else { } else {
// use frame position // use frame position
if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe)) if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos,
&start, &size, &keyframe))
return B_LAST_BUFFER_ERROR; return B_LAST_BUFFER_ERROR;
} }
@@ -571,7 +586,15 @@ mp4Reader::GetNextChunk(void *_cookie,
*chunkBuffer = cookie->buffer; *chunkBuffer = cookie->buffer;
*chunkSize = size; *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)
return B_LAST_BUFFER_ERROR;
return B_OK;
} }