ffmpeg: use new producer/consumer API for video decoding
This API allows us to send whole packets no matter how the video is formatted, and get frames out as they are ready (sometimes multiple frames per packets, which did not work well with the previous API). Change-Id: I0bd7d4706e330bb11d87cb41e93cfc6995b4b3a5 Reviewed-on: https://review.haiku-os.org/665 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
ce402e82f2
commit
5e14319a11
@@ -1239,76 +1239,75 @@ AVCodecDecoder::_UpdateMediaHeaderForAudioFrame()
|
|||||||
status_t
|
status_t
|
||||||
AVCodecDecoder::_DecodeNextVideoFrame()
|
AVCodecDecoder::_DecodeNextVideoFrame()
|
||||||
{
|
{
|
||||||
while (true) {
|
int error;
|
||||||
status_t loadingChunkStatus
|
int send_error;
|
||||||
= _LoadNextChunkIfNeededAndAssignStartTime();
|
|
||||||
if (loadingChunkStatus == B_LAST_BUFFER_ERROR)
|
|
||||||
return _FlushOneVideoFrameFromDecoderBuffer();
|
|
||||||
if (loadingChunkStatus != B_OK) {
|
|
||||||
TRACE("AVCodecDecoder::_DecodeNextVideoFrame(): error from "
|
|
||||||
"GetNextChunk(): %s\n", strerror(loadingChunkStatus));
|
|
||||||
return loadingChunkStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DO_PROFILING
|
#if DO_PROFILING
|
||||||
bigtime_t startTime = system_time();
|
bigtime_t startTime = system_time();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NOTE: In the FFMPEG 0.10.2 code example decoding_encoding.c, the
|
error = avcodec_receive_frame(fCodecContext, fRawDecodedPicture);
|
||||||
// length returned by avcodec_decode_video2() is used to update the
|
|
||||||
// packet buffer size (here it is fTempPacket.size). This way the
|
if (error == AVERROR(EAGAIN)) {
|
||||||
// packet buffer is allowed to contain incomplete frames so we are
|
do {
|
||||||
// required to buffer the packets between different calls to
|
status_t loadingChunkStatus
|
||||||
// _DecodeNextVideoFrame().
|
= _LoadNextChunkIfNeededAndAssignStartTime();
|
||||||
int gotVideoFrame = 0;
|
if (loadingChunkStatus == B_LAST_BUFFER_ERROR)
|
||||||
int encodedDataSizeInBytes = avcodec_decode_video2(fCodecContext,
|
return _FlushOneVideoFrameFromDecoderBuffer();
|
||||||
fRawDecodedPicture, &gotVideoFrame, &fTempPacket);
|
if (loadingChunkStatus != B_OK) {
|
||||||
if (encodedDataSizeInBytes < 0) {
|
TRACE("[v] AVCodecDecoder::_DecodeNextVideoFrame(): error from "
|
||||||
TRACE("[v] AVCodecDecoder: ignoring error in decoding frame %lld:"
|
"GetNextChunk(): %s\n", strerror(loadingChunkStatus));
|
||||||
" %d\n", fFrame, encodedDataSizeInBytes);
|
return loadingChunkStatus;
|
||||||
// NOTE: An error from avcodec_decode_video2() is ignored by the
|
}
|
||||||
// FFMPEG 0.10.2 example decoding_encoding.c. Only the packet
|
|
||||||
// buffers are flushed accordingly
|
char timestamp[AV_TS_MAX_STRING_SIZE];
|
||||||
|
av_ts_make_time_string(timestamp,
|
||||||
|
fTempPacket.dts, &fCodecContext->time_base);
|
||||||
|
TRACE("[v] Feed %d more bytes (dts %s)\n", fTempPacket.size,
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
send_error = avcodec_send_packet(fCodecContext, &fTempPacket);
|
||||||
|
if (send_error < 0 && send_error != AVERROR(EAGAIN)) {
|
||||||
|
TRACE("[v] AVCodecDecoder: ignoring error in decoding frame "
|
||||||
|
"%lld: %d\n", fFrame, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packet is consumed, clear it
|
||||||
fTempPacket.data = NULL;
|
fTempPacket.data = NULL;
|
||||||
fTempPacket.size = 0;
|
fTempPacket.size = 0;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fTempPacket.size -= encodedDataSizeInBytes;
|
error = avcodec_receive_frame(fCodecContext, fRawDecodedPicture);
|
||||||
fTempPacket.data += encodedDataSizeInBytes;
|
if (error != 0 && error != AVERROR(EAGAIN)) {
|
||||||
|
TRACE("[v] frame %lld - decoding error, error code: %d, "
|
||||||
|
"chunk size: %ld\n", fFrame, error, fChunkBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
bool gotNoVideoFrame = gotVideoFrame == 0;
|
} while (error != 0);
|
||||||
if (gotNoVideoFrame) {
|
|
||||||
TRACE("frame %lld - no picture yet, encodedDataSizeInBytes: %d, "
|
|
||||||
"chunk size: %ld\n", fFrame, encodedDataSizeInBytes,
|
|
||||||
fChunkBufferSize);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DO_PROFILING
|
|
||||||
bigtime_t formatConversionStart = system_time();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
status_t handleStatus = _HandleNewVideoFrameAndUpdateSystemState();
|
|
||||||
if (handleStatus != B_OK)
|
|
||||||
return handleStatus;
|
|
||||||
|
|
||||||
#if DO_PROFILING
|
|
||||||
bigtime_t doneTime = system_time();
|
|
||||||
decodingTime += formatConversionStart - startTime;
|
|
||||||
conversionTime += doneTime - formatConversionStart;
|
|
||||||
profileCounter++;
|
|
||||||
if (!(fFrame % 5)) {
|
|
||||||
printf("[v] profile: d1 = %lld, d2 = %lld (%lld) required %Ld\n",
|
|
||||||
decodingTime / profileCounter, conversionTime / profileCounter,
|
|
||||||
fFrame, bigtime_t(1000000LL / fOutputFrameRate));
|
|
||||||
decodingTime = 0;
|
|
||||||
conversionTime = 0;
|
|
||||||
profileCounter = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DO_PROFILING
|
||||||
|
bigtime_t formatConversionStart = system_time();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status_t handleStatus = _HandleNewVideoFrameAndUpdateSystemState();
|
||||||
|
if (handleStatus != B_OK)
|
||||||
|
return handleStatus;
|
||||||
|
|
||||||
|
#if DO_PROFILING
|
||||||
|
bigtime_t doneTime = system_time();
|
||||||
|
decodingTime += formatConversionStart - startTime;
|
||||||
|
conversionTime += doneTime - formatConversionStart;
|
||||||
|
profileCounter++;
|
||||||
|
if (!(fFrame % 5)) {
|
||||||
|
printf("[v] profile: d1 = %lld, d2 = %lld (%lld) required %Ld\n",
|
||||||
|
decodingTime / profileCounter, conversionTime / profileCounter,
|
||||||
|
fFrame, bigtime_t(1000000LL / fOutputFrameRate));
|
||||||
|
decodingTime = 0;
|
||||||
|
conversionTime = 0;
|
||||||
|
profileCounter = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user