From bac2b3f15ca3b7ac97c4211606583b0309f3d654 Mon Sep 17 00:00:00 2001 From: beveloper Date: Sun, 29 Feb 2004 18:53:57 +0000 Subject: [PATCH] When the decoder doesn't support the requested format, the raw decoder is utilized to provide a format conversion to the requested raw format. Added a few workarounds for applications that don't requst the required format but instead assume to get a specific one. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6815 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/media/MediaTrack.h | 14 +- src/kits/media/MediaTrack.cpp | 271 +++++++++++++++++++++++++++++++++- 2 files changed, 276 insertions(+), 9 deletions(-) diff --git a/headers/os/media/MediaTrack.h b/headers/os/media/MediaTrack.h index 27991d4aec..cf9fa4e502 100644 --- a/headers/os/media/MediaTrack.h +++ b/headers/os/media/MediaTrack.h @@ -81,7 +81,7 @@ public: // The data returned through ReadFrames() will be in the format that's // returned by this function. - status_t DecodedFormat(media_format *inout_format); + status_t DecodedFormat(media_format *inout_format, int32 flags = 0); // CountFrames and Duration return the total number of frame and the // total duration (expressed in microseconds) of a track. @@ -206,9 +206,16 @@ private: BPrivate::media::Encoder *encoder, media_codec_info *mci); +#ifdef __BUILDING_MEDIA_TRACK_CPP + status_t DecodedFormat(media_format *inout_format); +#endif + + void SetupWorkaround(); + bool SetupFormatTranslation(const media_format &from, media_format *to); + status_t fErr; BPrivate::media::Decoder *fDecoder; - int32 __unused__fDecoderID; + BPrivate::media::Decoder *fRawDecoder; BPrivate::media::MediaExtractor *fExtractor; int32 fStream; @@ -221,7 +228,8 @@ private: int32 fEncoderID; BPrivate::MediaWriter *fWriter; media_format fWriterFormat; - void *__unused__fExtractorCookie; + + uint32 fWorkaroundFlags; protected: int32 EncoderID() { return fEncoderID; }; diff --git a/src/kits/media/MediaTrack.cpp b/src/kits/media/MediaTrack.cpp index d98d488d41..11c6878603 100644 --- a/src/kits/media/MediaTrack.cpp +++ b/src/kits/media/MediaTrack.cpp @@ -3,13 +3,49 @@ * FILE: MediaTrack.cpp * DESCR: ***********************************************************************/ + +#define __BUILDING_MEDIA_TRACK_CPP + #include +#include #include #include "MediaExtractor.h" #include "PluginManager.h" #include "ReaderPlugin.h" #include "debug.h" +#define CONVERT_TO_INT32 1 // XXX test! this triggers a few bugs! + +// flags used for workarounds +enum { + FORCE_RAW_AUDIO = 0x0001, + FORCE_RAW_VIDEO = 0x0002, + FORCE_RAW_AUDIO_INT16_FORMAT = 0x0010, + FORCE_RAW_AUDIO_INT32_FORMAT = 0x0020, + FORCE_RAW_AUDIO_FLOAT_FORMAT = 0x0040, + FORCE_RAW_AUDIO_HOST_ENDIAN = 0x0100, + IGNORE_ENCODED_AUDIO = 0x1000, + IGNORE_ENCODED_VIDEO = 0x2000, +}; + +#define B_MEDIA_DISABLE_FORMAT_TRANSLATION 0x4000 // XXX move this (after name change?) to MediaDefs.h + +class RawDecoderChunkProvider : public ChunkProvider +{ +public: + RawDecoderChunkProvider(Decoder *decoder, int buffer_size, int frame_size); + virtual ~RawDecoderChunkProvider(); + + status_t GetNextChunk(void **chunkBuffer, int32 *chunkSize, media_header *mediaHeader); + +private: + Decoder *fDecoder; + void *fBuffer; + int fBufferSize; + int fFrameSize; +}; + + /************************************************************* * protected BMediaTrack *************************************************************/ @@ -17,6 +53,8 @@ BMediaTrack::~BMediaTrack() { CALLED(); + if (fRawDecoder) + _DestroyDecoder(fRawDecoder); if (fDecoder) _DestroyDecoder(fDecoder); } @@ -58,12 +96,23 @@ BMediaTrack::EncodedFormat(media_format *out_format) const *out_format = *fExtractor->EncodedFormat(fStream); + char s[200]; + string_for_format(*out_format, s, sizeof(s)); + printf("BMediaTrack::EncodedFormat: %s\n", s); + return B_OK; } status_t BMediaTrack::DecodedFormat(media_format *inout_format) +{ + return DecodedFormat(inout_format, 0); +} + + +status_t +BMediaTrack::DecodedFormat(media_format *inout_format, int32 flags) { CALLED(); if (!inout_format) @@ -71,7 +120,83 @@ BMediaTrack::DecodedFormat(media_format *inout_format) if (!fExtractor || !fDecoder) return B_NO_INIT; - return fDecoder->NegotiateOutputFormat(inout_format); + if (fRawDecoder) { + _DestroyDecoder(fRawDecoder); + fRawDecoder = 0; + } + + char s[200]; + + string_for_format(*inout_format, s, sizeof(s)); + printf("BMediaTrack::DecodedFormat: req1: %s\n", s); + + if ((fWorkaroundFlags & FORCE_RAW_AUDIO) || ((fWorkaroundFlags & IGNORE_ENCODED_AUDIO) && inout_format->type == B_MEDIA_ENCODED_AUDIO)) { + inout_format->type = B_MEDIA_RAW_AUDIO; + inout_format->u.raw_audio = media_multi_audio_format::wildcard; + } + if ((fWorkaroundFlags & FORCE_RAW_VIDEO) || ((fWorkaroundFlags & IGNORE_ENCODED_VIDEO) && inout_format->type == B_MEDIA_ENCODED_VIDEO)) { + inout_format->type = B_MEDIA_RAW_VIDEO; + inout_format->u.raw_video = media_raw_video_format::wildcard; + } + if (inout_format->type == B_MEDIA_RAW_AUDIO) { + if (fWorkaroundFlags & FORCE_RAW_AUDIO_HOST_ENDIAN) + inout_format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; + if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT) + inout_format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; + if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT32_FORMAT) + inout_format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; + if (fWorkaroundFlags & FORCE_RAW_AUDIO_FLOAT_FORMAT) + inout_format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; + } + + string_for_format(*inout_format, s, sizeof(s)); + printf("BMediaTrack::DecodedFormat: req2: %s\n", s); + + media_format requested_format = *inout_format; + + status_t res; + + res = fDecoder->NegotiateOutputFormat(inout_format); + + string_for_format(*inout_format, s, sizeof(s)); + printf("BMediaTrack::DecodedFormat: nego: %s\n", s); + + if (inout_format->type == 0) + debugger("Decoder didn't set output format type"); + if (inout_format->type == B_MEDIA_RAW_AUDIO) { + if (inout_format->u.raw_audio.byte_order == 0) + debugger("Decoder didn't set raw audio output byte order"); + if (inout_format->u.raw_audio.format == 0) + debugger("Decoder didn't set raw audio output sample format"); + if (inout_format->u.raw_audio.buffer_size <= 0) + debugger("Decoder didn't set raw audio output buffer size"); + } + if (inout_format->type == B_MEDIA_RAW_VIDEO) { + if (inout_format->u.raw_video.display.format == 0) + debugger("Decoder didn't set raw video output color space"); + if (inout_format->u.raw_video.display.line_width == 0) + debugger("Decoder didn't set raw video output line_width"); + if (inout_format->u.raw_video.display.line_count == 0) + debugger("Decoder didn't set raw video output line_count"); + if (inout_format->u.raw_video.display.bytes_per_row == 0) + debugger("Decoder didn't set raw video output bytes_per_row"); + } + + if (0 == (flags & B_MEDIA_DISABLE_FORMAT_TRANSLATION)) { + if (requested_format.type == B_MEDIA_RAW_AUDIO + && inout_format->type == B_MEDIA_RAW_AUDIO + && requested_format.u.raw_audio.format != 0 + && requested_format.u.raw_audio.format != inout_format->u.raw_audio.format) { + if (SetupFormatTranslation(*inout_format, &requested_format)) { + *inout_format = requested_format; + } + } + } + +// string_for_format(*inout_format, s, sizeof(s)); +// printf("BMediaTrack::DecodedFormat: res: %s\n", s); + + return res; } @@ -79,7 +204,9 @@ int64 BMediaTrack::CountFrames() const { CALLED(); - return fExtractor ? fExtractor->CountFrames(fStream) : 0; + int64 frames = fExtractor ? fExtractor->CountFrames(fStream) : 0; + printf("BMediaTrack::CountFrames: %Ld\n", frames); + return frames; } @@ -87,7 +214,9 @@ bigtime_t BMediaTrack::Duration() const { CALLED(); - return fExtractor ? fExtractor->Duration(fStream) : 0; + bigtime_t duration = fExtractor ? fExtractor->Duration(fStream) : 0; + printf("BMediaTrack::Duration: %Ld\n", duration); + return duration; } @@ -130,8 +259,11 @@ BMediaTrack::ReadFrames(void *out_buffer, media_header header; memset(&header, 0, sizeof(header)); // always clear it first, as the decoder doesn't set all fields - - result = fDecoder->Decode(out_buffer, out_frameCount, &header, info); + + if (fRawDecoder) + result = fRawDecoder->Decode(out_buffer, out_frameCount, &header, info); + else + result = fDecoder->Decode(out_buffer, out_frameCount, &header, info); if (result == B_OK) { fCurFrame += *out_frameCount; fCurTime = header.start_time; @@ -141,6 +273,9 @@ BMediaTrack::ReadFrames(void *out_buffer, } if (mh) *mh = header; + + printf("BMediaTrack::ReadFrames: %Ld frames, start-time %Ld\n", *out_frameCount, header.start_time); + return result; } @@ -182,12 +317,20 @@ BMediaTrack::SeekToTime(bigtime_t *inout_time, printf("BMediaTrack::SeekToTime: extractor seek failed\n"); return result; } - + result = fDecoder->Seek(seekTo, 0, &frame, seekTime, &time); if (result != B_OK) { printf("BMediaTrack::SeekToTime: decoder seek failed\n"); return result; } + + if (fRawDecoder) { + result = fRawDecoder->Seek(seekTo, 0, &frame, seekTime, &time); + if (result != B_OK) { + printf("BMediaTrack::SeekToTime: raw decoder seek failed\n"); + return result; + } + } *inout_time = time; fCurFrame = frame; @@ -231,6 +374,14 @@ BMediaTrack::SeekToFrame(int64 *inout_frame, return result; printf("BMediaTrack::SeekToFrame: decoder seek failed\n"); } + + if (fRawDecoder) { + result = fRawDecoder->Seek(seekTo, seekFrame, &frame, 0, &time); + if (result != B_OK) { + printf("BMediaTrack::SeekToFrame: raw decoder seek failed\n"); + return result; + } + } *inout_frame = frame; fCurFrame = frame; @@ -453,11 +604,16 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor *extractor, int32 stream) { CALLED(); + fWorkaroundFlags = 0; + fRawDecoder = 0; fExtractor = extractor; fStream = stream; fErr = B_OK; + SetupWorkaround(); + if (fExtractor->CreateDecoder(fStream, &fDecoder, &fMCI) != B_OK) { + ERROR("BMediaTrack::BMediaTrack: Error: creating decoder failed\n"); // we do not set fErr here, because ReadChunk should still work fDecoder = 0; return; @@ -482,6 +638,78 @@ BMediaTrack::BMediaTrack(BPrivate::MediaWriter *writer, UNIMPLEMENTED(); } +void +BMediaTrack::SetupWorkaround() +{ + app_info ainfo; + thread_info tinfo; + + get_thread_info(find_thread(0), &tinfo); + be_roster->GetRunningAppInfo(tinfo.team, &ainfo); + + if (strcmp(ainfo.signature, "application/x-vnd.marcone-soundplay") == 0) { + fWorkaroundFlags = FORCE_RAW_AUDIO | FORCE_RAW_AUDIO_INT16_FORMAT | FORCE_RAW_AUDIO_HOST_ENDIAN; + printf("BMediaTrack::SetupWorkaround: SoundPlay workaround active\n"); + } + if (strcmp(ainfo.signature, "application/x-vnd.Be.MediaPlayer") == 0) { + fWorkaroundFlags = IGNORE_ENCODED_AUDIO | IGNORE_ENCODED_VIDEO; + printf("BMediaTrack::SetupWorkaround: MediaPlayer workaround active\n"); + } + +#if CONVERT_TO_INT32 // XXX test + if (!(fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT)) + fWorkaroundFlags |= FORCE_RAW_AUDIO_INT32_FORMAT; +#endif +} + +bool +BMediaTrack::SetupFormatTranslation(const media_format &from, media_format *to) +{ + char s[200]; + status_t res; + + string_for_format(from, s, sizeof(s)); + printf("BMediaTrack::SetupFormatTranslation: from: %s\n", s); + + res = _CreateDecoder(&fRawDecoder, from); + if (res != B_OK) { + printf("BMediaTrack::SetupFormatTranslation: _CreateDecoder failed\n"); + return false; + } + + // XXX video? + int buffer_size = from.u.raw_audio.buffer_size; + int frame_size = (from.u.raw_audio.format & 15) * from.u.raw_audio.channel_count; + + fRawDecoder->Setup(new RawDecoderChunkProvider(fDecoder, buffer_size, frame_size)); + + media_format from_temp = from; + res = fRawDecoder->Setup(&from_temp, 0, 0); + if (res != B_OK) { + printf("BMediaTrack::SetupFormatTranslation: Setup failed\n"); + goto error; + } + + string_for_format(*to, s, sizeof(s)); + printf("BMediaTrack::SetupFormatTranslation: to: %s\n", s); + + res = fRawDecoder->NegotiateOutputFormat(to); + if (res != B_OK) { + printf("BMediaTrack::SetupFormatTranslation: NegotiateOutputFormat failed\n"); + goto error; + } + + string_for_format(*to, s, sizeof(s)); + printf("BMediaTrack::SetupFormatTranslation: res: %s\n", s); + + return true; + +error: + _DestroyDecoder(fRawDecoder); + fRawDecoder = 0; + return false; +} + /* // unimplemented BMediaTrack::BMediaTrack() @@ -538,3 +766,34 @@ status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; } status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; } + +RawDecoderChunkProvider::RawDecoderChunkProvider(Decoder *decoder, int buffer_size, int frame_size) +{ + printf("RawDecoderChunkProvider: buffer_size %d, frame_size %d\n", buffer_size, frame_size); + fDecoder = decoder; + fFrameSize = frame_size; + fBufferSize = buffer_size; + fBuffer = malloc(buffer_size); +} + +RawDecoderChunkProvider::~RawDecoderChunkProvider() +{ + free(fBuffer); +} + +status_t +RawDecoderChunkProvider::GetNextChunk(void **chunkBuffer, int32 *chunkSize, + media_header *mediaHeader) +{ + int64 frames; + media_decode_info info; + status_t res = fDecoder->Decode(fBuffer, &frames, mediaHeader, &info); + if (res == B_OK) { + *chunkBuffer = fBuffer; + *chunkSize = frames * fFrameSize; + printf("RawDecoderChunkProvider::GetNextChunk, %Ld frames, %ld bytes, start-time %Ld\n", frames, *chunkSize, mediaHeader->start_time); + } else { + printf("RawDecoderChunkProvider::GetNextChunk failed\n"); + } + return res; +}