* 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:
parent
3ad603ace4
commit
42c1d42429
@ -27,8 +27,8 @@
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// Std Headers
|
||||
#include <map.h>
|
||||
#include <map>
|
||||
|
||||
|
||||
struct ChunkIndex {
|
||||
uint32 stream;
|
||||
|
@ -25,15 +25,15 @@
|
||||
#ifndef _MP4_ATOM_H
|
||||
#define _MP4_ATOM_H
|
||||
|
||||
#include "MP4Structs.h"
|
||||
|
||||
#include <File.h>
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaFormats.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// Std Headers
|
||||
#include <map.h>
|
||||
#include <map>
|
||||
|
||||
#include "MP4Structs.h"
|
||||
|
||||
/*
|
||||
AtomBase
|
||||
|
@ -22,38 +22,45 @@
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <iostream.h>
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <SupportKit.h>
|
||||
|
||||
#include "MP4Parser.h"
|
||||
#include "MP4FileReader.h"
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <SupportKit.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
extern AtomBase *getAtom(BPositionIO *pStream);
|
||||
|
||||
|
||||
MP4FileReader::MP4FileReader(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;
|
||||
}
|
||||
|
||||
|
||||
MP4FileReader::~MP4FileReader()
|
||||
{
|
||||
theStream = 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++) {
|
||||
aAtomBase = GetChildAtom(uint32('mdat'),index);
|
||||
@ -62,32 +69,40 @@ AtomBase *aAtomBase;
|
||||
return pPosition >= aMdatAtom->getEOF();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
atomChildren[TotalChildren++] = pChildAtom;
|
||||
if (childAtom) {
|
||||
atomChildren[TotalChildren++] = childAtom;
|
||||
return true;
|
||||
}
|
||||
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)) {
|
||||
// found match, skip if offset non zero.
|
||||
if (offset == 0) {
|
||||
@ -110,7 +125,9 @@ AtomBase *MP4FileReader::GetChildAtom(uint32 patomType, uint32 offset)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32 MP4FileReader::CountChildAtoms(uint32 patomType)
|
||||
|
||||
uint32
|
||||
MP4FileReader::CountChildAtoms(uint32 patomType)
|
||||
{
|
||||
uint32 count = 0;
|
||||
|
||||
@ -120,9 +137,11 @@ uint32 MP4FileReader::CountChildAtoms(uint32 patomType)
|
||||
return count;
|
||||
}
|
||||
|
||||
MVHDAtom *MP4FileReader::getMVHDAtom()
|
||||
|
||||
MVHDAtom*
|
||||
MP4FileReader::getMVHDAtom()
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
AtomBase *aAtomBase;
|
||||
|
||||
if (theMVHDAtom == NULL) {
|
||||
aAtomBase = GetChildAtom(uint32('mvhd'));
|
||||
@ -133,9 +152,11 @@ AtomBase *aAtomBase;
|
||||
return theMVHDAtom;
|
||||
}
|
||||
|
||||
void MP4FileReader::BuildSuperIndex()
|
||||
|
||||
void
|
||||
MP4FileReader::BuildSuperIndex()
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
AtomBase *aAtomBase;
|
||||
|
||||
for (uint32 stream=0;stream<getStreamCount();stream++) {
|
||||
aAtomBase = GetChildAtom(uint32('trak'),stream);
|
||||
@ -146,7 +167,7 @@ AtomBase *aAtomBase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add end of file to index
|
||||
aAtomBase = GetChildAtom(uint32('mdat'),0);
|
||||
if (aAtomBase) {
|
||||
@ -155,147 +176,160 @@ AtomBase *aAtomBase;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 MP4FileReader::getMovieTimeScale()
|
||||
|
||||
uint32
|
||||
MP4FileReader::getMovieTimeScale()
|
||||
{
|
||||
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
|
||||
return (CountChildAtoms(uint32('trak')));
|
||||
return CountChildAtoms(uint32('trak'));
|
||||
}
|
||||
|
||||
bigtime_t MP4FileReader::getVideoDuration(uint32 stream_index)
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
|
||||
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
|
||||
}
|
||||
|
||||
bigtime_t
|
||||
MP4FileReader::getVideoDuration(uint32 streamIndex)
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
|
||||
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bigtime_t MP4FileReader::getAudioDuration(uint32 stream_index)
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
|
||||
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
|
||||
}
|
||||
|
||||
bigtime_t
|
||||
MP4FileReader::getAudioDuration(uint32 streamIndex)
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
|
||||
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bigtime_t MP4FileReader::getMaxDuration()
|
||||
|
||||
bigtime_t
|
||||
MP4FileReader::getMaxDuration()
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
int32 video_index,audio_index;
|
||||
video_index = -1;
|
||||
audio_index = -1;
|
||||
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);
|
||||
|
||||
for (uint32 i = 0; i < getStreamCount(); i++) {
|
||||
aAtomBase = GetChildAtom(uint32('trak'), i);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsActive())) {
|
||||
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio()) {
|
||||
audio_index = int32(i);
|
||||
audioIndex = int32(i);
|
||||
}
|
||||
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo()) {
|
||||
video_index = int32(i);
|
||||
videoIndex = int32(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((video_index >= 0) && (audio_index >= 0)) {
|
||||
return MAX(getVideoDuration(video_index),getAudioDuration(audio_index));
|
||||
if (videoIndex >= 0 && audioIndex >= 0) {
|
||||
return max_c(getVideoDuration(videoIndex),
|
||||
getAudioDuration(audioIndex));
|
||||
}
|
||||
if ((video_index < 0) && (audio_index >= 0)) {
|
||||
return getAudioDuration(audio_index);
|
||||
if (videoIndex < 0 && audioIndex >= 0) {
|
||||
return getAudioDuration(audioIndex);
|
||||
}
|
||||
if ((video_index >= 0) && (audio_index < 0)) {
|
||||
return getVideoDuration(video_index);
|
||||
if (videoIndex >= 0 && audioIndex < 0) {
|
||||
return getVideoDuration(videoIndex);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 MP4FileReader::getVideoFrameCount(uint32 stream_index)
|
||||
|
||||
uint32
|
||||
MP4FileReader::getVideoFrameCount(uint32 streamIndex)
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
|
||||
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
|
||||
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 MP4FileReader::getAudioFrameCount(uint32 stream_index)
|
||||
|
||||
uint32
|
||||
MP4FileReader::getAudioFrameCount(uint32 streamIndex)
|
||||
{
|
||||
if (IsAudio(stream_index)) {
|
||||
return uint32(((getAudioDuration(stream_index) * AudioFormat(stream_index)->SampleRate) / 1000000L) + 0.5);
|
||||
if (IsAudio(streamIndex)) {
|
||||
return uint32(((getAudioDuration(streamIndex)
|
||||
* AudioFormat(streamIndex)->SampleRate) / 1000000L) + 0.5);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MP4FileReader::IsVideo(uint32 stream_index)
|
||||
{
|
||||
// Look for a trak with a vmhd atom
|
||||
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if (aAtomBase) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo());
|
||||
}
|
||||
|
||||
// No trak
|
||||
bool
|
||||
MP4FileReader::IsVideo(uint32 streamIndex)
|
||||
{
|
||||
// Look for a 'trak' with a vmhd atom
|
||||
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
if (aAtomBase)
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo();
|
||||
|
||||
// No track
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MP4FileReader::IsAudio(uint32 stream_index)
|
||||
{
|
||||
// Look for a trak with a smhd atom
|
||||
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if (aAtomBase) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio());
|
||||
}
|
||||
|
||||
// No trak
|
||||
bool
|
||||
MP4FileReader::IsAudio(uint32 streamIndex)
|
||||
{
|
||||
// Look for a 'trak' with a smhd atom
|
||||
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
|
||||
if (aAtomBase)
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio();
|
||||
|
||||
// No track
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 MP4FileReader::getFirstFrameInChunk(uint32 stream_index, uint32 pChunkID)
|
||||
|
||||
uint32
|
||||
MP4FileReader::getFirstFrameInChunk(uint32 streamIndex, uint32 pChunkID)
|
||||
{
|
||||
// Find Track
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
|
||||
return aTrakAtom->getFirstSampleInChunk(pChunkID);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
|
||||
|
||||
uint32
|
||||
MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
|
||||
{
|
||||
// Find Track
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
@ -303,10 +337,9 @@ uint32 MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
uint32 ChunkNo = 1;
|
||||
|
||||
if (IsAudio(stream_index)) {
|
||||
ChunkNo = pFrameNo;
|
||||
}
|
||||
|
||||
if (IsAudio(stream_index))
|
||||
ChunkNo = pFrameNo;
|
||||
|
||||
if (IsVideo(stream_index)) {
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
|
||||
@ -320,7 +353,9 @@ uint32 MP4FileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
|
||||
|
||||
uint64
|
||||
MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
|
||||
{
|
||||
// Find Track
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
@ -336,7 +371,6 @@ uint64 MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
|
||||
}
|
||||
|
||||
if (IsVideo(stream_index)) {
|
||||
|
||||
if (pFrameNo < aTrakAtom->FrameCount()) {
|
||||
// Get Sample for Frame
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
@ -365,11 +399,13 @@ uint64 MP4FileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t MP4FileReader::ParseFile()
|
||||
|
||||
status_t
|
||||
MP4FileReader::ParseFile()
|
||||
{
|
||||
AtomBase *aChild;
|
||||
while (IsEndOfFile() == false) {
|
||||
@ -389,7 +425,9 @@ status_t MP4FileReader::ParseFile()
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
const mp4_main_header *MP4FileReader::MovMainHeader()
|
||||
|
||||
const mp4_main_header*
|
||||
MP4FileReader::MovMainHeader()
|
||||
{
|
||||
// Fill In theMainHeader
|
||||
// uint32 micro_sec_per_frame;
|
||||
@ -409,10 +447,10 @@ const mp4_main_header *MP4FileReader::MovMainHeader()
|
||||
theMainHeader.flags = 0;
|
||||
theMainHeader.initial_frames = 0;
|
||||
|
||||
while ( videoStream < theMainHeader.streams ) {
|
||||
if (IsVideo(videoStream) && IsActive(videoStream)) {
|
||||
while (videoStream < theMainHeader.streams) {
|
||||
if (IsVideo(videoStream) && IsActive(videoStream))
|
||||
break;
|
||||
}
|
||||
|
||||
videoStream++;
|
||||
}
|
||||
|
||||
@ -429,17 +467,18 @@ const mp4_main_header *MP4FileReader::MovMainHeader()
|
||||
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 *MP4FileReader::AudioFormat(uint32 stream_index, size_t *size = 0)
|
||||
|
||||
const AudioMetaData *
|
||||
MP4FileReader::AudioFormat(uint32 stream_index, size_t *size)
|
||||
{
|
||||
if (IsAudio(stream_index)) {
|
||||
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if (aAtomBase) {
|
||||
@ -470,22 +509,21 @@ const AudioMetaData *MP4FileReader::AudioFormat(uint32 stream_index, size_t *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const VideoMetaData *MP4FileReader::VideoFormat(uint32 stream_index)
|
||||
|
||||
const VideoMetaData*
|
||||
MP4FileReader::VideoFormat(uint32 stream_index)
|
||||
{
|
||||
if (IsVideo(stream_index)) {
|
||||
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
|
||||
aAtomBase = aTrakAtom->GetChildAtom(uint32('stsd'),0);
|
||||
|
||||
if (aAtomBase) {
|
||||
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
|
||||
|
||||
VideoDescription aVideoDescription = aSTSDAtom->getAsVideo();
|
||||
|
||||
|
||||
theVideo.compression = aVideoDescription.codecid;
|
||||
|
||||
theVideo.width = aVideoDescription.theVideoSampleEntry.Width;
|
||||
@ -506,17 +544,19 @@ const VideoMetaData *MP4FileReader::VideoFormat(uint32 stream_index)
|
||||
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
|
||||
|
||||
theVideo.FrameRate = ((aSTTSAtom->getSUMCounts() * 1000000.0L) / aTrakAtom->Duration(1));
|
||||
|
||||
|
||||
return &theVideo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
theStreamHeader.length = 0;
|
||||
@ -530,7 +570,7 @@ const mp4_stream_header *MP4FileReader::StreamFormat(uint32 stream_index)
|
||||
theStreamHeader.scale = 1000000L;
|
||||
theStreamHeader.length = getVideoFrameCount(stream_index);
|
||||
}
|
||||
|
||||
|
||||
if (IsAudio(stream_index)) {
|
||||
theStreamHeader.rate = uint32(AudioFormat(stream_index)->SampleRate);
|
||||
theStreamHeader.scale = 1;
|
||||
@ -538,26 +578,27 @@ const mp4_stream_header *MP4FileReader::StreamFormat(uint32 stream_index)
|
||||
theStreamHeader.sample_size = AudioFormat(stream_index)->SampleSize;
|
||||
theStreamHeader.suggested_buffer_size = theStreamHeader.rate * theStreamHeader.sample_size;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
if (IsAudio(stream_index)) {
|
||||
|
||||
// We read audio in chunk by chunk so chunk size is chunk size
|
||||
uint32 ChunkNo = pFrameNo;
|
||||
off_t Chunk_Start = aTrakAtom->getOffsetForChunk(ChunkNo);
|
||||
uint32 ChunkSize = theChunkSuperIndex.getChunkSize(stream_index,ChunkNo,Chunk_Start);
|
||||
|
||||
|
||||
return ChunkSize;
|
||||
}
|
||||
|
||||
|
||||
if (IsVideo(stream_index)) {
|
||||
if (pFrameNo < aTrakAtom->FrameCount()) {
|
||||
// We read video in Sample by Sample so we use get Sample Size
|
||||
@ -565,18 +606,19 @@ uint32 MP4FileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo)
|
||||
return aTrakAtom->getSizeForSample(SampleNo);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
return aTrakAtom->IsSyncSample(SampleNo);
|
||||
}
|
||||
@ -584,38 +626,44 @@ bool MP4FileReader::IsKeyFrame(uint32 stream_index, uint32 pFrameNo)
|
||||
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);
|
||||
*size = getChunkSize(stream_index, pFrameNo);
|
||||
|
||||
|
||||
if ((*start > 0) && (*size > 0)) {
|
||||
*keyframe = IsKeyFrame(stream_index, pFrameNo);
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
return aTrakAtom->IsActive();
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
bool MP4FileReader::IsSupported(BPositionIO *source)
|
||||
bool
|
||||
MP4FileReader::IsSupported(BPositionIO *source)
|
||||
{
|
||||
AtomBase *aAtom;
|
||||
|
||||
aAtom = getAtom(source);
|
||||
if (aAtom) {
|
||||
return (aAtom->IsKnown());
|
||||
}
|
||||
AtomBase *aAtom = getAtom(source);
|
||||
if (aAtom)
|
||||
return aAtom->IsKnown();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// Std Headers
|
||||
#include <map.h>
|
||||
#include <map>
|
||||
|
||||
#include "MP4Atom.h"
|
||||
|
||||
|
@ -22,6 +22,12 @@
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef MP4_STRUCTS_H
|
||||
#define MP4_STRUCTS_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
#define AUDIO_NONE 'NONE'
|
||||
#define AUDIO_RAW 'raw '
|
||||
@ -33,8 +39,7 @@
|
||||
#define AUDIO_MPEG3_CBR 0x6D730055
|
||||
|
||||
// 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 max_bytes_per_sec;
|
||||
uint32 padding_granularity;
|
||||
@ -273,3 +278,5 @@ struct VideoDescription {
|
||||
uint8 *theVOL;
|
||||
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
|
||||
* 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 "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
|
||||
#ifdef TRACE_MP4_READER
|
||||
#define TRACE printf
|
||||
# define TRACE printf
|
||||
#else
|
||||
#define TRACE(a...)
|
||||
# define TRACE(a...)
|
||||
#endif
|
||||
|
||||
#define ERROR(a...) fprintf(stderr, a)
|
||||
|
||||
struct mp4_cookie
|
||||
{
|
||||
|
||||
struct mp4_cookie {
|
||||
unsigned stream;
|
||||
char * buffer;
|
||||
unsigned buffer_size;
|
||||
@ -77,17 +81,20 @@ mp4Reader::mp4Reader()
|
||||
TRACE("mp4Reader::mp4Reader\n");
|
||||
}
|
||||
|
||||
|
||||
mp4Reader::~mp4Reader()
|
||||
{
|
||||
delete theFileReader;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
mp4Reader::Copyright()
|
||||
{
|
||||
return "MPEG4 & libMP4, " B_UTF8_COPYRIGHT " by David McPaul";
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
mp4Reader::Sniff(int32 *streamCount)
|
||||
{
|
||||
@ -118,13 +125,14 @@ mp4Reader::Sniff(int32 *streamCount)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mp4Reader::GetFileFormatInfo(media_file_format *mff)
|
||||
{
|
||||
mff->capabilities = media_file_format::B_READABLE
|
||||
| media_file_format::B_KNOWS_ENCODED_VIDEO
|
||||
| media_file_format::B_KNOWS_ENCODED_AUDIO
|
||||
| media_file_format::B_IMPERFECTLY_SEEKABLE;
|
||||
mff->capabilities = media_file_format::B_READABLE
|
||||
| media_file_format::B_KNOWS_ENCODED_VIDEO
|
||||
| media_file_format::B_KNOWS_ENCODED_AUDIO
|
||||
| media_file_format::B_IMPERFECTLY_SEEKABLE;
|
||||
mff->family = B_QUICKTIME_FORMAT_FAMILY;
|
||||
mff->version = 100;
|
||||
strcpy(mff->mime_type, "video/quicktime");
|
||||
@ -133,6 +141,7 @@ mp4Reader::GetFileFormatInfo(media_file_format *mff)
|
||||
strcpy(mff->pretty_name, "MPEG-4 (MP4) file format");
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
{
|
||||
@ -180,40 +189,46 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
cookie->chunk_pos = 1;
|
||||
|
||||
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->frames_per_sec_rate = stream_header->rate;
|
||||
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) {
|
||||
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->frames_per_sec_rate = stream_header->rate;
|
||||
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) {
|
||||
cookie->bytes_per_sec_rate = audio_format->PacketSize;
|
||||
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;
|
||||
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 {
|
||||
cookie->bytes_per_sec_rate = 128000;
|
||||
cookie->bytes_per_sec_scale = 8;
|
||||
cookie->frames_per_sec_rate = 16000;
|
||||
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) ||
|
||||
(audio_format->compression == AUDIO_RAW) ||
|
||||
(audio_format->compression == AUDIO_TWOS1) ||
|
||||
(audio_format->compression == AUDIO_TWOS2)) {
|
||||
if (audio_format->compression == AUDIO_NONE
|
||||
|| 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)) {
|
||||
if (B_OK != formats.GetFormatFor(description, format))
|
||||
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.channel_count = audio_format->NoOfChannels;
|
||||
@ -463,7 +478,7 @@ mp4Reader::FreeCookie(void *_cookie)
|
||||
|
||||
status_t
|
||||
mp4Reader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
|
||||
media_format *format, const void **infoBuffer, size_t *infoSize)
|
||||
media_format *format, const void **infoBuffer, size_t *infoSize)
|
||||
{
|
||||
mp4_cookie *cookie = (mp4_cookie *)_cookie;
|
||||
|
||||
@ -477,9 +492,7 @@ mp4Reader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
|
||||
|
||||
|
||||
status_t
|
||||
mp4Reader::Seek(void *cookie,
|
||||
uint32 seekTo,
|
||||
int64 *frame, bigtime_t *time)
|
||||
mp4Reader::Seek(void *cookie, uint32 seekTo, int64 *frame, bigtime_t *time)
|
||||
{
|
||||
|
||||
// We should seek to nearest keyframe requested
|
||||
@ -515,21 +528,23 @@ mp4Reader::Seek(void *cookie,
|
||||
|
||||
|
||||
status_t
|
||||
mp4Reader::GetNextChunk(void *_cookie,
|
||||
const void **chunkBuffer, size_t *chunkSize,
|
||||
media_header *mediaHeader)
|
||||
mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
||||
size_t *chunkSize, media_header *mediaHeader)
|
||||
{
|
||||
mp4_cookie *cookie = (mp4_cookie *)_cookie;
|
||||
|
||||
int64 start; uint32 size; bool keyframe;
|
||||
int64 start;
|
||||
uint32 size;
|
||||
bool keyframe;
|
||||
|
||||
if (cookie->audio) {
|
||||
// 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;
|
||||
} else {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -571,7 +586,15 @@ mp4Reader::GetNextChunk(void *_cookie,
|
||||
|
||||
*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)
|
||||
return B_LAST_BUFFER_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user