From 8a822b7c859482b7391ab7bad9423b6bbef2b237 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Thu, 17 Dec 2015 18:24:01 -0500 Subject: [PATCH] Revert "AVCodecDecoder: use swresample to interleave audio channels." Commit 856cc59e58bb83de4a69daa680748ba9b52592d8 didn't really "fix" anything; it just broke audio pretty much everywhere but YouTube, and there videos play at 2x speed so it wasn't really worth it. Stopgap solution for #12509. --- .../media/plugins/ffmpeg/AVCodecDecoder.cpp | 65 +++++++++++-------- .../media/plugins/ffmpeg/AVCodecDecoder.h | 9 +-- src/add-ons/media/plugins/ffmpeg/Jamfile | 1 - 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index 275bbcaa26..c1c2bb4e4a 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -5,14 +5,12 @@ * Copyright (C) 2004 Marcus Overhagen * Copyright (C) 2009 Stephan Amßus * Copyright (C) 2014 Colin Günther - * Copyright (C) 2015 Adrien Destugues * * All rights reserved. Distributed under the terms of the MIT License. */ //! libavcodec based decoder for Haiku - #include "AVCodecDecoder.h" #include @@ -89,7 +87,6 @@ AVCodecDecoder::AVCodecDecoder() fIsAudio(false), fCodec(NULL), fContext(avcodec_alloc_context3(NULL)), - fResampleContext(NULL), fDecodedData(NULL), fDecodedDataSizeInBytes(0), fPostProcessedDecodedPicture(avcodec_alloc_frame()), @@ -118,6 +115,7 @@ AVCodecDecoder::AVCodecDecoder() fAudioDecodeError(false), fDecodedDataBuffer(avcodec_alloc_frame()), + fDecodedDataBufferOffset(0), fDecodedDataBufferSize(0) { TRACE("AVCodecDecoder::AVCodecDecoder()\n"); @@ -146,7 +144,6 @@ AVCodecDecoder::~AVCodecDecoder() if (fCodecInitDone) avcodec_close(fContext); - swr_free(&fResampleContext); free(fChunkBuffer); free(fDecodedData); @@ -232,7 +229,8 @@ AVCodecDecoder::Setup(media_format* ioEncodedFormat, const void* infoBuffer, } else { if (fIsAudio) { fBlockAlign - = ioEncodedFormat->u.encoded_audio.output.buffer_size; + = ioEncodedFormat->u.encoded_audio.output + .buffer_size; TRACE(" using buffer_size as block align: %d\n", fBlockAlign); } @@ -272,6 +270,7 @@ AVCodecDecoder::SeekedTo(int64 frame, bigtime_t time) free(fChunkBuffer); fChunkBuffer = NULL; fChunkBufferSize = 0; + fDecodedDataBufferOffset = 0; fDecodedDataBufferSize = 0; fDecodedDataSizeInBytes = 0; @@ -359,6 +358,7 @@ AVCodecDecoder::_NegotiateAudioOutputFormat(media_format* inOutFormat) fChunkBuffer = NULL; fChunkBufferSize = 0; fAudioDecodeError = false; + fDecodedDataBufferOffset = 0; fDecodedDataBufferSize = 0; _ResetTempPacket(); @@ -405,13 +405,6 @@ AVCodecDecoder::_NegotiateAudioOutputFormat(media_format* inOutFormat) if (fRawDecodedAudio->opaque == NULL) return B_NO_MEMORY; - fResampleContext = swr_alloc_set_opts(NULL, - fContext->channel_layout, fContext->request_sample_fmt, - fContext->sample_rate, - fContext->channel_layout, fContext->sample_fmt, fContext->sample_rate, - 0, NULL); - swr_init(fResampleContext); - TRACE(" bit_rate = %d, sample_rate = %d, channels = %d, " "output frame size: %d, count: %ld, rate: %.2f\n", fContext->bit_rate, fContext->sample_rate, fContext->channels, @@ -901,20 +894,24 @@ AVCodecDecoder::_MoveAudioFramesToRawDecodedAudioAndUpdateStartTimes() assert(fRawDecodedAudio->nb_samples < fOutputFrameCount); assert(fOutputFrameRate > 0); - // Some decoders do not support format conversion on themselves, or use - // "planar" audio (each channel separated instead of interleaved samples). - // In that case, we use swresample to convert the data (and it is - // smart enough to do just a copy, when possible) - int32 frames = swr_convert(fResampleContext, fRawDecodedAudio->data, - fOutputFrameCount - fRawDecodedAudio->nb_samples, - (const uint8_t**)fDecodedDataBuffer->data, - fDecodedDataBuffer->nb_samples); - if (frames < 0) - debugger("resampling failed"); + int32 frames = min_c(fOutputFrameCount - fRawDecodedAudio->nb_samples, + fDecodedDataBufferSize / fOutputFrameSize); + if (frames == 0) + debugger("fDecodedDataBufferSize not multiple of frame size!"); + size_t remainingSize = frames * fOutputFrameSize; - // libswresample handles all the buffering for us, how nice of them! - fDecodedDataBufferSize = 0; +#if 0 + // Some decoders do not support format conversion on themselves, or use + // "planar" audio (each channel separated instead of interleaved samples). + // If this is a problem we will need to use swresample to convert the data + // here, instead of directly copying it. + swr_convert(fResampleContext, fRawDecodedAudio->data, + fDecodedDataBuffer->data + fDecodedDataBufferOffset, frames); +#else + memcpy(fRawDecodedAudio->data[0], fDecodedDataBuffer->data[0] + + fDecodedDataBufferOffset, remainingSize); +#endif bool firstAudioFramesCopiedToRawDecodedAudio = fRawDecodedAudio->data[0] != fDecodedData; @@ -931,6 +928,19 @@ AVCodecDecoder::_MoveAudioFramesToRawDecodedAudioAndUpdateStartTimes() fRawDecodedAudio->data[0] += remainingSize; fRawDecodedAudio->linesize[0] += remainingSize; fRawDecodedAudio->nb_samples += frames; + + fDecodedDataBufferOffset += remainingSize; + fDecodedDataBufferSize -= remainingSize; + + // Update start times accordingly + bigtime_t framesTimeInterval = static_cast( + (1000000LL * frames) / fOutputFrameRate); + fDecodedDataBuffer->pkt_dts += framesTimeInterval; + // Start time of buffer is updated in case that it contains + // more audio frames to move. + fTempPacket.dts += framesTimeInterval; + // Start time of fTempPacket is updated in case the fTempPacket + // contains more audio frames to decode. } @@ -952,7 +962,8 @@ AVCodecDecoder::_MoveAudioFramesToRawDecodedAudioAndUpdateStartTimes() After this function returns successfully the caller can safely make the following assumptions: 1. fDecodedDataBufferSize is greater than zero. - 2. fDecodedDataBuffer contains audio frames. + 2. fDecodedDataBufferOffset is set to zero. + 3. fDecodedDataBuffer contains audio frames. \returns B_OK on successfully decoding one audio frame chunk. \returns B_LAST_BUFFER_ERROR No more audio frame chunks available. From @@ -964,7 +975,7 @@ AVCodecDecoder::_DecodeNextAudioFrameChunk() { assert(fDecodedDataBufferSize == 0); - while (fDecodedDataBufferSize == 0) { + while(fDecodedDataBufferSize == 0) { status_t loadingChunkStatus = _LoadNextChunkIfNeededAndAssignStartTime(); if (loadingChunkStatus != B_OK) @@ -1011,6 +1022,7 @@ AVCodecDecoder::_DecodeNextAudioFrameChunk() Also see "Note" below. 2. fTempPacket was updated to exclude the data chunk that was consumed by avcodec_decode_audio4(). + 3. fDecodedDataBufferOffset is set to zero. When this function failed to decode at least one audio frame due to a decoding error the caller can safely make the following assumptions: @@ -1037,6 +1049,7 @@ AVCodecDecoder::_DecodeSomeAudioFramesIntoEmptyDecodedDataBuffer() assert(fTempPacket.size > 0); avcodec_get_frame_defaults(fDecodedDataBuffer); + fDecodedDataBufferOffset = 0; int gotAudioFrame = 0; int encodedDataSizeInBytes = avcodec_decode_audio4(fContext, diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h index ee2b4eb901..16906d02b5 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h @@ -4,7 +4,6 @@ * Copyright (C) 2001 Axel Dörfler. * Copyright (C) 2004 Marcus Overhagen. * Copyright (C) 2009 Stephan Aßmus . - * Copyright (C) 2015 Adrien Destugues . * * All rights reserved. Distributed under the terms of the MIT License. */ @@ -13,17 +12,13 @@ //! libavcodec based decoder for Haiku - #include - extern "C" { #include "avcodec.h" - #include "swresample.h" #include "swscale.h" } - #include "DecoderPlugin.h" #include "ReaderPlugin.h" @@ -108,7 +103,6 @@ private: // FFmpeg related members AVCodec* fCodec; AVCodecContext* fContext; - SwrContext* fResampleContext; uint8_t* fDecodedData; size_t fDecodedDataSizeInBytes; AVFrame* fPostProcessedDecodedPicture; @@ -118,9 +112,7 @@ private: bool fCodecInitDone; gfx_convert_func fFormatConversionFunc; -#if USE_SWS_FOR_COLOR_SPACE_CONVERSION SwsContext* fSwsContext; -#endif char* fExtraData; int fExtraDataSize; @@ -137,6 +129,7 @@ private: bool fAudioDecodeError; AVFrame* fDecodedDataBuffer; + int32 fDecodedDataBufferOffset; int32 fDecodedDataBufferSize; AVPacket fTempPacket; diff --git a/src/add-ons/media/plugins/ffmpeg/Jamfile b/src/add-ons/media/plugins/ffmpeg/Jamfile index 9c3eeaa6b6..c3efdd0bcf 100644 --- a/src/add-ons/media/plugins/ffmpeg/Jamfile +++ b/src/add-ons/media/plugins/ffmpeg/Jamfile @@ -47,7 +47,6 @@ for architectureObject in [ MultiArchSubDirSetup ] { UseHeaders [ FDirName $(ffmpegHeaders) libavformat ] ; UseHeaders [ FDirName $(ffmpegHeaders) libavutil ] ; UseHeaders [ FDirName $(ffmpegHeaders) libswscale ] ; - UseHeaders [ FDirName $(ffmpegHeaders) libswresample ] ; Addon [ MultiArchDefaultGristFiles ffmpeg ] : $(sources)