Add ALAC and AAC decoder support
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26997 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -118,7 +118,7 @@ void AtomBase::DisplayAtoms()
|
|||||||
void AtomBase::DisplayAtoms(uint32 pindent)
|
void AtomBase::DisplayAtoms(uint32 pindent)
|
||||||
{
|
{
|
||||||
Indent(pindent);
|
Indent(pindent);
|
||||||
printf("%s\n",getAtomName());
|
printf("(%s)\n",getAtomName());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomBase::Indent(uint32 pindent)
|
void AtomBase::Indent(uint32 pindent)
|
||||||
@@ -278,7 +278,7 @@ AtomContainer::~AtomContainer()
|
|||||||
void AtomContainer::DisplayAtoms(uint32 pindent)
|
void AtomContainer::DisplayAtoms(uint32 pindent)
|
||||||
{
|
{
|
||||||
Indent(pindent);
|
Indent(pindent);
|
||||||
printf("%ld:%s\n",TotalChildren,getAtomName());
|
printf("%ld:(%s)\n",TotalChildren,getAtomName());
|
||||||
pindent++;
|
pindent++;
|
||||||
// for each child
|
// for each child
|
||||||
for (uint32 i = 0;i < TotalChildren;i++) {
|
for (uint32 i = 0;i < TotalChildren;i++) {
|
||||||
|
|||||||
@@ -1747,7 +1747,6 @@ void HDLRAtom::OnProcessMetaData()
|
|||||||
|
|
||||||
char *HDLRAtom::OnGetAtomName()
|
char *HDLRAtom::OnGetAtomName()
|
||||||
{
|
{
|
||||||
printf("%s %s:",(char *)&(theHeader.handler_type),name);
|
|
||||||
return "MPEG-4 Handler Reference Atom ";
|
return "MPEG-4 Handler Reference Atom ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ struct mp4_cookie {
|
|||||||
uint32 frame_pos;
|
uint32 frame_pos;
|
||||||
uint32 frames_per_sec_rate;
|
uint32 frames_per_sec_rate;
|
||||||
uint32 frames_per_sec_scale;
|
uint32 frames_per_sec_scale;
|
||||||
|
uint32 frame_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -188,7 +189,7 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
// frame_count is actually sample_count for audio - makes media_player happy but david sad
|
// 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->frame_count = theFileReader->getFrameCount(cookie->stream) * audio_format->FrameSize;
|
||||||
cookie->duration = theFileReader->getAudioDuration(cookie->stream);
|
cookie->duration = theFileReader->getAudioDuration(cookie->stream);
|
||||||
|
|
||||||
cookie->audio = true;
|
cookie->audio = true;
|
||||||
|
|
||||||
if (stream_header->scale && stream_header->rate) {
|
if (stream_header->scale && stream_header->rate) {
|
||||||
@@ -199,7 +200,7 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
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",
|
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using both)\n",
|
||||||
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
||||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using both)\n",
|
TRACE("samples_per_sec_rate %ld, samples_per_sec_scale %ld (using both)\n",
|
||||||
cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||||
} else if (stream_header->rate) {
|
} else if (stream_header->rate) {
|
||||||
cookie->bytes_per_sec_rate = stream_header->rate * audio_format->SampleSize
|
cookie->bytes_per_sec_rate = stream_header->rate * audio_format->SampleSize
|
||||||
@@ -209,7 +210,7 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
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",
|
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using rate)\n",
|
||||||
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
||||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using rate)\n",
|
TRACE("samples_per_sec_rate %ld, samples_per_sec_scale %ld (using rate)\n",
|
||||||
cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||||
} else {
|
} else {
|
||||||
cookie->bytes_per_sec_rate = 128000;
|
cookie->bytes_per_sec_rate = 128000;
|
||||||
@@ -297,7 +298,8 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
case 'alac':
|
case 'alac':
|
||||||
TRACE("AAC audio (mp4a) or ALAC audio\n");
|
TRACE("AAC audio (mp4a) or ALAC audio\n");
|
||||||
|
|
||||||
format->u.encoded_audio.output.frame_rate = cookie->frames_per_sec_rate / cookie->frames_per_sec_scale;;
|
format->u.encoded_audio.output.frame_rate = cookie->frames_per_sec_rate / cookie->frames_per_sec_scale;
|
||||||
|
|
||||||
format->u.encoded_audio.output.channel_count = audio_format->NoOfChannels;
|
format->u.encoded_audio.output.channel_count = audio_format->NoOfChannels;
|
||||||
format->u.encoded_audio.output.format = media_raw_audio_format::B_AUDIO_SHORT;
|
format->u.encoded_audio.output.format = media_raw_audio_format::B_AUDIO_SHORT;
|
||||||
format->u.encoded_audio.output.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
|
format->u.encoded_audio.output.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
|
||||||
@@ -307,18 +309,21 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
// ALAC is 4096 samples per frame
|
// ALAC is 4096 samples per frame
|
||||||
|
|
||||||
format->u.encoded_audio.frame_size = audio_format->FrameSize;
|
format->u.encoded_audio.frame_size = audio_format->FrameSize;
|
||||||
|
cookie->frame_size = audio_format->FrameSize;
|
||||||
|
|
||||||
format->u.encoded_audio.output.buffer_size = audio_format->BufferSize;
|
format->u.encoded_audio.output.buffer_size = audio_format->BufferSize;
|
||||||
|
|
||||||
// Average BitRate = (TotalBytes * 8 * (SampleRate / FrameSize)) / TotalFrames
|
// Average BitRate = (TotalBytes * 8 * (SampleRate / FrameSize)) / TotalFrames
|
||||||
// Setting a bitrate seems to cause more problems than it solves
|
// Setting a bitrate seems to cause more problems than it solves
|
||||||
format->u.encoded_audio.bit_rate = audio_format->BitRate; // Should be 64000 * channelcount
|
|
||||||
|
format->u.encoded_audio.bit_rate = audio_format->NoOfChannels * 64000; // Should be 64000 * channelcount
|
||||||
|
|
||||||
TRACE("Audio NoOfChannels %d, SampleSize %d, SampleRate %f, FrameSize %ld\n",audio_format->NoOfChannels, audio_format->SampleSize, audio_format->SampleRate, audio_format->FrameSize);
|
TRACE("Audio NoOfChannels %d, SampleSize %d, SampleRate %f, FrameSize %ld\n",audio_format->NoOfChannels, audio_format->SampleSize, audio_format->SampleRate, audio_format->FrameSize);
|
||||||
|
|
||||||
TRACE("Audio frame_rate %f, channel_count %ld, format %ld, buffer_size %ld, frame_size %ld, bit_rate %f\n",
|
TRACE("Audio frame_rate %f, channel_count %ld, format %ld, buffer_size %ld, frame_size %ld, bit_rate %f\n",
|
||||||
format->u.encoded_audio.output.frame_rate, format->u.encoded_audio.output.channel_count, format->u.encoded_audio.output.format,format->u.encoded_audio.output.buffer_size, format->u.encoded_audio.frame_size, format->u.encoded_audio.bit_rate);
|
format->u.encoded_audio.output.frame_rate, format->u.encoded_audio.output.channel_count, format->u.encoded_audio.output.format,format->u.encoded_audio.output.buffer_size, format->u.encoded_audio.frame_size, format->u.encoded_audio.bit_rate);
|
||||||
|
|
||||||
TRACE("Track %d MP4 Audio FrameCount %ld\n",cookie->stream,theFileReader->getFrameCount(cookie->stream));
|
TRACE("Track %d MP4 Audio FrameCount %ld Duration %Ld\n",cookie->stream,theFileReader->getFrameCount(cookie->stream),cookie->duration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -378,6 +383,7 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
|
|
||||||
cookie->audio = false;
|
cookie->audio = false;
|
||||||
cookie->line_count = theFileReader->MovMainHeader()->height;
|
cookie->line_count = theFileReader->MovMainHeader()->height;
|
||||||
|
cookie->frame_size = 1;
|
||||||
|
|
||||||
if (stream_header->scale && stream_header->rate) {
|
if (stream_header->scale && stream_header->rate) {
|
||||||
cookie->frames_per_sec_rate = stream_header->rate;
|
cookie->frames_per_sec_rate = stream_header->rate;
|
||||||
@@ -525,7 +531,7 @@ mp4Reader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
|
|||||||
*infoBuffer = audio_format->theDecoderConfig;
|
*infoBuffer = audio_format->theDecoderConfig;
|
||||||
*infoSize = audio_format->DecoderConfigSize;
|
*infoSize = audio_format->DecoderConfigSize;
|
||||||
} else {
|
} else {
|
||||||
printf("No stream Info for stream %d\n",cookie->stream);
|
ERROR("No stream Info for stream %d\n",cookie->stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -536,21 +542,18 @@ status_t
|
|||||||
mp4Reader::Seek(void *cookie, uint32 flags, int64 *frame, bigtime_t *time)
|
mp4Reader::Seek(void *cookie, uint32 flags, int64 *frame, bigtime_t *time)
|
||||||
{
|
{
|
||||||
// seek to the requested time or frame
|
// seek to the requested time or frame
|
||||||
|
|
||||||
mp4_cookie *mp4cookie = (mp4_cookie *)cookie;
|
mp4_cookie *mp4cookie = (mp4_cookie *)cookie;
|
||||||
|
|
||||||
if (flags & B_MEDIA_SEEK_TO_TIME) {
|
if (flags & B_MEDIA_SEEK_TO_TIME) {
|
||||||
// frame = (time * rate) / fps / 1000000LL
|
// frame = (time * rate) / fps / 1000000LL
|
||||||
*frame = ((*time * mp4cookie->frames_per_sec_rate) / (int64)mp4cookie->frames_per_sec_scale) / 1000000LL;
|
*frame = ((*time * mp4cookie->frames_per_sec_rate) / (int64)mp4cookie->frames_per_sec_scale) / 1000000LL;
|
||||||
TRACE("Time %Ld to Frame %Ld\n",*time, *frame);
|
mp4cookie->frame_pos = *frame / mp4cookie->frame_size;
|
||||||
mp4cookie->frame_pos = *frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & B_MEDIA_SEEK_TO_FRAME) {
|
if (flags & B_MEDIA_SEEK_TO_FRAME) {
|
||||||
// time = frame * 1000000LL * fps / rate
|
// time = frame * 1000000LL * fps / rate
|
||||||
TRACE("Frame %Ld to Time %Ld\n", *frame, *time);
|
|
||||||
*time = (*frame * 1000000LL * (int64)mp4cookie->frames_per_sec_scale) / mp4cookie->frames_per_sec_rate;
|
*time = (*frame * 1000000LL * (int64)mp4cookie->frames_per_sec_scale) / mp4cookie->frames_per_sec_rate;
|
||||||
mp4cookie->frame_pos = *frame;
|
mp4cookie->frame_pos = *frame / mp4cookie->frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("mp4Reader::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
TRACE("mp4Reader::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
||||||
@@ -585,10 +588,8 @@ mp4Reader::FindKeyFrame(void* cookie, uint32 flags,
|
|||||||
(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
|
(flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
|
||||||
*time, *frame);
|
*time, *frame);
|
||||||
|
|
||||||
if (mp4cookie->audio) {
|
// Audio does not have keyframes? Or all audio frames are keyframes?
|
||||||
// Audio does not have keyframes? Or all audio frames are keyframes?
|
if (mp4cookie->audio == false) {
|
||||||
return B_OK;
|
|
||||||
} else {
|
|
||||||
while (*frame > 0 && *frame <= mp4cookie->frame_count) {
|
while (*frame > 0 && *frame <= mp4cookie->frame_count) {
|
||||||
keyframe = theFileReader->IsKeyFrame(mp4cookie->stream, *frame);
|
keyframe = theFileReader->IsKeyFrame(mp4cookie->stream, *frame);
|
||||||
|
|
||||||
@@ -627,8 +628,8 @@ mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
|||||||
uint32 size;
|
uint32 size;
|
||||||
bool keyframe;
|
bool keyframe;
|
||||||
|
|
||||||
if (theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe) == false) {
|
if (theFileReader->GetNextChunkInfo(cookie->stream, (cookie->frame_pos / cookie->frame_size), &start, &size, &keyframe) == false) {
|
||||||
TRACE("LAST BUFFER ERROR\n");
|
TRACE("LAST BUFFER ERROR %ld\n",cookie->frame_pos);
|
||||||
return B_LAST_BUFFER_ERROR;
|
return B_LAST_BUFFER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,12 +639,14 @@ mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
|||||||
cookie->buffer = new char [cookie->buffer_size];
|
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) {
|
if (cookie->audio) {
|
||||||
// TRACE("Audio stream %d: frame %ld expected start time %lld output size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
// TRACE("Audio");
|
||||||
mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
|
mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
|
||||||
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
||||||
} else {
|
} else {
|
||||||
// TRACE("Video stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
// TRACE("Video");
|
||||||
mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
|
mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
|
||||||
mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
||||||
mediaHeader->u.encoded_video.first_active_line = 0;
|
mediaHeader->u.encoded_video.first_active_line = 0;
|
||||||
@@ -651,12 +654,10 @@ mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
|||||||
mediaHeader->u.encoded_video.field_number = 0;
|
mediaHeader->u.encoded_video.field_number = 0;
|
||||||
mediaHeader->u.encoded_video.field_sequence = cookie->frame_pos;
|
mediaHeader->u.encoded_video.field_sequence = cookie->frame_pos;
|
||||||
}
|
}
|
||||||
|
// 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");
|
||||||
|
|
||||||
mediaHeader->start_time = bigtime_t(cookie->frame_pos * 1000000.0 * cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
|
cookie->frame_pos += cookie->frame_size;
|
||||||
cookie->frame_pos++;
|
|
||||||
|
|
||||||
// TRACE("stream %d: start_time %.6f\n", cookie->stream, mediaHeader->start_time / 1000000.0);
|
|
||||||
|
|
||||||
*chunkBuffer = cookie->buffer;
|
*chunkBuffer = cookie->buffer;
|
||||||
*chunkSize = size;
|
*chunkSize = size;
|
||||||
|
|
||||||
@@ -664,8 +665,10 @@ mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
|||||||
if (bytesRead < B_OK)
|
if (bytesRead < B_OK)
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
|
|
||||||
if (bytesRead < (ssize_t)size)
|
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_LAST_BUFFER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user