* Simplified "extra data" handling/allocation code a bit.

* Added debugging facility to dump the first 100 packets of a video stream
  to a debug file on the Desktop.
* When needing to flush packets, avcodec_flush_buffers() is unfortunately
  not reliable. For audio codecs, the work around was to close and reopen
  the codec in Seek(). Do this also for video codecs. Makes H.264 more
  reliable here.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31503 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2009-07-10 14:20:48 +00:00
parent 981f1b1135
commit 219858ad31
@@ -28,6 +28,14 @@
# define TRACE(x...) # define TRACE(x...)
#endif #endif
//#define LOG_STREAM_TO_FILE
#ifdef LOG_STREAM_TO_FILE
# include <File.h>
static BFile sStreamLogFile("/boot/home/Desktop/AVCodecDebugStream.raw",
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
static int sDumpedPackets = 0;
#endif
struct wave_format_ex { struct wave_format_ex {
uint16 format_tag; uint16 format_tag;
@@ -103,8 +111,8 @@ AVCodecDecoder::~AVCodecDecoder()
free(fInputPicture); free(fInputPicture);
free(fContext); free(fContext);
delete [] fExtraData; delete[] fExtraData;
delete [] fOutputBuffer; delete[] fOutputBuffer;
} }
@@ -182,38 +190,40 @@ AVCodecDecoder::Setup(media_format* ioEncodedFormat, const void* infoBuffer,
if (gCodecTable[i].family == descr.family if (gCodecTable[i].family == descr.family
&& gCodecTable[i].fourcc == cid) { && gCodecTable[i].fourcc == cid) {
fCodec = avcodec_find_decoder(gCodecTable[i].id); fCodec = avcodec_find_decoder(gCodecTable[i].id);
if (!fCodec) { if (fCodec == NULL) {
TRACE("AVCodecDecoder: unable to find the correct ffmpeg " TRACE("AVCodecDecoder: unable to find the correct FFmpeg "
"decoder (id = %d)!!!\n",gCodecTable[i].id); "decoder (id = %d)\n", gCodecTable[i].id);
return B_ERROR; return B_ERROR;
} }
TRACE("AVCodecDecoder: found decoder %s\n",fCodec->name); TRACE("AVCodecDecoder: found decoder %s\n",fCodec->name);
const void* extraData = infoBuffer;
fExtraDataSize = infoSize;
if (gCodecTable[i].family == B_WAV_FORMAT_FAMILY if (gCodecTable[i].family == B_WAV_FORMAT_FAMILY
&& infoSize >= sizeof(wave_format_ex)) { && infoSize >= sizeof(wave_format_ex)) {
const wave_format_ex *wfmt_data // Special case extra data in B_WAV_FORMAT_FAMILY
= (const wave_format_ex *)infoBuffer; const wave_format_ex* waveFormatData
size_t wfmt_size = infoSize; = (const wave_format_ex*)infoBuffer;
if (wfmt_data && wfmt_size) {
fBlockAlign = wfmt_data->block_align; size_t waveFormatSize = infoSize;
fExtraDataSize = wfmt_data->extra_size; if (waveFormatData != NULL && waveFormatSize > 0) {
if (fExtraDataSize) { fBlockAlign = waveFormatData->block_align;
fExtraData = new char [fExtraDataSize]; fExtraDataSize = waveFormatData->extra_size;
memcpy(fExtraData, wfmt_data + 1, fExtraDataSize); // skip the wave_format_ex from the extra data.
} extraData = waveFormatData + 1;
} }
} else { } else {
fBlockAlign fBlockAlign
= ioEncodedFormat->u.encoded_audio.output.buffer_size; = ioEncodedFormat->u.encoded_audio.output.buffer_size;
}
printf("XXX extra data size %ld\n", infoSize);
if (extraData != NULL && fExtraDataSize > 0) {
TRACE("AVCodecDecoder: extra data size %ld\n", infoSize); TRACE("AVCodecDecoder: extra data size %ld\n", infoSize);
fExtraDataSize = infoSize; fExtraData = new(std::nothrow) char[fExtraDataSize];
if (fExtraDataSize) { if (fExtraData != NULL)
fExtraData = new(std::nothrow) char[fExtraDataSize]; memcpy(fExtraData, infoBuffer, fExtraDataSize);
if (fExtraData != NULL) else
memcpy(fExtraData, infoBuffer, fExtraDataSize); fExtraDataSize = 0;
else
fExtraDataSize = 0;
}
} }
fInputFormat = *ioEncodedFormat; fInputFormat = *ioEncodedFormat;
@@ -231,13 +241,18 @@ AVCodecDecoder::Seek(uint32 seekTo, int64 seekFrame, int64* frame,
bigtime_t seekTime, bigtime_t* time) bigtime_t seekTime, bigtime_t* time)
{ {
// Reset the FFmpeg codec to flush buffers, so we keep the sync // Reset the FFmpeg codec to flush buffers, so we keep the sync
// TODO: Maybe that should be done for video codecs, too? #if 1
if (fIsAudio && fCodecInitDone) { if (fCodecInitDone) {
fCodecInitDone = false; fCodecInitDone = false;
avcodec_close(fContext); avcodec_close(fContext);
fCodecInitDone = (avcodec_open(fContext, fCodec) >= 0); fCodecInitDone = (avcodec_open(fContext, fCodec) >= 0);
} }
#else
// For example, this doesn't work on the H.264 codec. :-/
if (fCodecInitDone)
avcodec_flush_buffers(fContext);
#endif
if (seekTo == B_MEDIA_SEEK_TO_TIME) { if (seekTo == B_MEDIA_SEEK_TO_TIME) {
TRACE("AVCodecDecoder::Seek by time "); TRACE("AVCodecDecoder::Seek by time ");
TRACE("from frame %Ld and time %.6f TO Required Time %.6f. ", TRACE("from frame %Ld and time %.6f TO Required Time %.6f. ",
@@ -388,11 +403,11 @@ AVCodecDecoder::_NegotiateVideoOutputFormat(media_format* inOutFormat)
fOutputFrameRate = fOutputVideoFormat.field_rate; fOutputFrameRate = fOutputVideoFormat.field_rate;
fContext->extradata = (uint8_t *)fExtraData; fContext->extradata = (uint8_t*)fExtraData;
fContext->extradata_size = fExtraDataSize; fContext->extradata_size = fExtraDataSize;
// if (fInputFormat.MetaDataSize() > 0) { // if (fInputFormat.MetaDataSize() > 0) {
// fContext->extradata = (uint8_t *)fInputFormat.MetaData(); // fContext->extradata = (uint8_t*)fInputFormat.MetaData();
// fContext->extradata_size = fInputFormat.MetaDataSize(); // fContext->extradata_size = fInputFormat.MetaDataSize();
// } // }
@@ -564,6 +579,15 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
"GetNextChunk(): %s\n", strerror(err)); "GetNextChunk(): %s\n", strerror(err));
return err; return err;
} }
#ifdef LOG_STREAM_TO_FILE
if (sDumpedPackets < 100) {
sStreamLogFile.Write(data, size);
printf("wrote %ld bytes\n", size);
sDumpedPackets++;
} else if (sDumpedPackets == 100)
sStreamLogFile.Unset();
#endif
if (firstRun) { if (firstRun) {
firstRun = false; firstRun = false;