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
This commit is contained in:
@@ -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; };
|
||||
|
||||
@@ -3,13 +3,49 @@
|
||||
* FILE: MediaTrack.cpp
|
||||
* DESCR:
|
||||
***********************************************************************/
|
||||
|
||||
#define __BUILDING_MEDIA_TRACK_CPP
|
||||
|
||||
#include <MediaTrack.h>
|
||||
#include <Roster.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user