* 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;
@@ -182,39 +190,41 @@ 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* waveFormatData
= (const wave_format_ex*)infoBuffer; = (const wave_format_ex*)infoBuffer;
size_t wfmt_size = infoSize;
if (wfmt_data && wfmt_size) { size_t waveFormatSize = infoSize;
fBlockAlign = wfmt_data->block_align; if (waveFormatData != NULL && waveFormatSize > 0) {
fExtraDataSize = wfmt_data->extra_size; fBlockAlign = waveFormatData->block_align;
if (fExtraDataSize) { fExtraDataSize = waveFormatData->extra_size;
fExtraData = new char [fExtraDataSize]; // skip the wave_format_ex from the extra data.
memcpy(fExtraData, wfmt_data + 1, fExtraDataSize); 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;
if (fExtraDataSize) {
fExtraData = new(std::nothrow) char[fExtraDataSize]; fExtraData = new(std::nothrow) char[fExtraDataSize];
if (fExtraData != NULL) if (fExtraData != NULL)
memcpy(fExtraData, infoBuffer, fExtraDataSize); memcpy(fExtraData, infoBuffer, fExtraDataSize);
else else
fExtraDataSize = 0; fExtraDataSize = 0;
} }
}
fInputFormat = *ioEncodedFormat; fInputFormat = *ioEncodedFormat;
return B_OK; return B_OK;
@@ -231,12 +241,17 @@ 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 ");
@@ -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;