diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index 20b88cf3f2..8067d3e6bf 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -119,6 +119,7 @@ AVCodecDecoder::AVCodecDecoder() fDecodedDataBuffer(av_frame_alloc()), fDecodedDataBufferOffset(0), fDecodedDataBufferSize(0), + fTempPacket(NULL), fBufferSinkContext(NULL), fBufferSourceContext(NULL), fFilterGraph(NULL), @@ -168,6 +169,8 @@ AVCodecDecoder::~AVCodecDecoder() #endif delete[] fExtraData; + + av_packet_free(&fTempPacket); } @@ -335,9 +338,10 @@ AVCodecDecoder::Decode(void* outBuffer, int64* outFrameCount, void AVCodecDecoder::_ResetTempPacket() { - av_init_packet(&fTempPacket); - fTempPacket.size = 0; - fTempPacket.data = NULL; + if (fTempPacket == NULL) + fTempPacket = av_packet_alloc(); + fTempPacket->size = 0; + fTempPacket->data = NULL; } @@ -700,7 +704,7 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount, status_t AVCodecDecoder::_DecodeNextAudioFrame() { - assert(fTempPacket.size >= 0); + assert(fTempPacket->size >= 0); assert(fDecodedDataSizeInBytes == 0); // _DecodeNextAudioFrame needs to be called on empty fDecodedData only! // If this assert holds wrong we have a bug somewhere. @@ -862,10 +866,10 @@ AVCodecDecoder::_CheckAndFixConditionsThatHintAtBrokenAudioCodeBelow() "buffer! %" B_PRId32 "\n", fDecodedDataBufferSize); fDecodedDataBufferSize = 0; } - if (fTempPacket.size < 0) { + if (fTempPacket->size < 0) { fprintf(stderr, "Decoding read past the end of the temp packet! %d\n", - fTempPacket.size); - fTempPacket.size = 0; + fTempPacket->size); + fTempPacket->size = 0; } } @@ -1003,7 +1007,7 @@ AVCodecDecoder::_MoveAudioFramesToRawDecodedAudioAndUpdateStartTimes() fDecodedDataBuffer->pkt_dts += framesTimeInterval; // Start time of buffer is updated in case that it contains // more audio frames to move. - fTempPacket.dts += framesTimeInterval; + fTempPacket->dts += framesTimeInterval; // Start time of fTempPacket is updated in case the fTempPacket // contains more audio frames to decode. } @@ -1056,10 +1060,10 @@ AVCodecDecoder::_DecodeNextAudioFrameChunk() if (!fAudioDecodeError) { // Report failure if not done already - int32 chunkBufferOffset = fTempPacket.data - fChunkBuffer; + int32 chunkBufferOffset = fTempPacket->data - fChunkBuffer; printf("########### audio decode error, " - "fTempPacket.size %d, fChunkBuffer data offset %" B_PRId32 - "\n", fTempPacket.size, chunkBufferOffset); + "fTempPacket->size %d, fChunkBuffer data offset %" B_PRId32 + "\n", fTempPacket->size, chunkBufferOffset); fAudioDecodeError = true; } @@ -1080,7 +1084,7 @@ AVCodecDecoder::_DecodeNextAudioFrameChunk() This function assumes to be called only when the following assumptions hold true: 1. fDecodedDataBufferSize equals zero. - 2. fTempPacket.size is greater than zero. + 2. fTempPacket->size is greater than zero. After this function returns successfully the caller can safely make the following assumptions: @@ -1093,7 +1097,7 @@ AVCodecDecoder::_DecodeNextAudioFrameChunk() When this function failed to decode at least one audio frame due to a decoding error the caller can safely make the following assumptions: 1. fDecodedDataBufferSize equals zero. - 2. fTempPacket.size equals zero. + 2. fTempPacket->size equals zero. Note: It is possible that there wasn't any audio frame decoded into fDecodedDataBuffer after calling this function. This is normal and can @@ -1122,10 +1126,10 @@ AVCodecDecoder::_DecodeSomeAudioFramesIntoEmptyDecodedDataBuffer() if (error == AVERROR(EAGAIN)) { // We need to feed more data into the decoder - avcodec_send_packet(fCodecContext, &fTempPacket); + avcodec_send_packet(fCodecContext, fTempPacket); // All the data is always consumed by avcodec_send_packet - fTempPacket.size = 0; + fTempPacket->size = 0; // Try again to see if we can get some decoded audio out now error = avcodec_receive_frame(fCodecContext, fDecodedDataBuffer); @@ -1258,19 +1262,19 @@ AVCodecDecoder::_DecodeNextVideoFrame() 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, + fTempPacket->dts, &fCodecContext->time_base); + TRACE("[v] Feed %d more bytes (dts %s)\n", fTempPacket->size, timestamp); - send_error = avcodec_send_packet(fCodecContext, &fTempPacket); + 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.size = 0; + fTempPacket->data = NULL; + fTempPacket->size = 0; error = avcodec_receive_frame(fCodecContext, fRawDecodedPicture); if (error != 0 && error != AVERROR(EAGAIN)) { @@ -1367,7 +1371,7 @@ AVCodecDecoder::_ApplyEssentialVideoContainerPropertiesToContext() status_t AVCodecDecoder::_LoadNextChunkIfNeededAndAssignStartTime() { - if (fTempPacket.size > 0) + if (fTempPacket->size > 0) return B_OK; const void* chunkBuffer = NULL; @@ -1386,9 +1390,9 @@ AVCodecDecoder::_LoadNextChunkIfNeededAndAssignStartTime() if (chunkBufferPaddingStatus != B_OK) return chunkBufferPaddingStatus; - fTempPacket.data = fChunkBuffer; - fTempPacket.size = fChunkBufferSize; - fTempPacket.dts = chunkMediaHeader.start_time; + fTempPacket->data = fChunkBuffer; + fTempPacket->size = fChunkBufferSize; + fTempPacket->dts = chunkMediaHeader.start_time; // Let FFMPEG handle the correct relationship between start_time and // decoded a/v frame. By doing so we are simply copying the way how it // is implemented in ffplay.c for video frames (for audio frames it diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h index 5469f56ae0..c958038ca4 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h @@ -154,7 +154,7 @@ private: int32 fDecodedDataBufferOffset; int32 fDecodedDataBufferSize; - AVPacket fTempPacket; + AVPacket* fTempPacket; // video deinterlace feature AVFilterContext* fBufferSinkContext; diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp index cde20a338e..bd54353930 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp @@ -534,12 +534,11 @@ AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize, status_t ret; // Encode one audio chunk/frame. - AVPacket packet; - av_init_packet(&packet); + AVPacket* packet = av_packet_alloc(); // By leaving these NULL, we let the encoder allocate memory as it needs. // This way we don't risk iving a too small buffer. - packet.data = NULL; - packet.size = 0; + packet->data = NULL; + packet->size = 0; int gotPacket = 0; @@ -552,6 +551,7 @@ AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize, if (count < 0) { TRACE(" avcodec_encode_audio() failed filling data: %d\n", count); + av_packet_free(&packet); return B_ERROR; } @@ -561,11 +561,11 @@ AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize, fFramesWritten += fFrame->nb_samples; ret = avcodec_send_frame(fCodecContext, fFrame); - gotPacket = avcodec_receive_packet(fCodecContext, &packet) == 0; + gotPacket = avcodec_receive_packet(fCodecContext, packet) == 0; } else { // If called with NULL, ask the encoder to flush any buffers it may // have pending. - ret = avcodec_receive_packet(fCodecContext, &packet); + ret = avcodec_receive_packet(fCodecContext, packet); gotPacket = (ret == 0); } @@ -574,6 +574,7 @@ AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize, if (ret != 0) { TRACE(" avcodec_encode_audio() failed: %s\n", strerror(ret)); + av_packet_free(&packet); return B_ERROR; } @@ -581,23 +582,23 @@ AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize, if (gotPacket) { // Setup media_encode_info, most important is the time stamp. - info->start_time = packet.pts; + info->start_time = packet->pts; - if (packet.flags & AV_PKT_FLAG_KEY) + if (packet->flags & AV_PKT_FLAG_KEY) info->flags = B_MEDIA_KEY_FRAME; else info->flags = 0; // We got a packet out of the encoder, write it to the output stream - ret = WriteChunk(packet.data, packet.size, info); + ret = WriteChunk(packet->data, packet->size, info); if (ret != B_OK) { TRACE(" error writing chunk: %s\n", strerror(ret)); - av_packet_unref(&packet); + av_packet_free(&packet); return ret; } } - av_packet_unref(&packet); + av_packet_free(&packet); return B_OK; } diff --git a/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp b/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp index 67e51ce0d6..416de43e26 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp @@ -72,7 +72,7 @@ public: private: AVFormatContext* fFormatContext; AVStream* fStream; - AVPacket fPacket; + AVPacket* fPacket; // Since different threads may write to the target, // we need to protect the file position and I/O by a lock. BLocker* fStreamLock; @@ -87,13 +87,14 @@ AVFormatWriter::StreamCookie::StreamCookie(AVFormatContext* context, fStream(NULL), fStreamLock(streamLock) { - av_init_packet(&fPacket); + fPacket = av_packet_alloc(); } AVFormatWriter::StreamCookie::~StreamCookie() { // fStream is freed automatically when the codec context is closed + av_packet_free(&fPacket); } @@ -105,7 +106,7 @@ AVFormatWriter::StreamCookie::Init(media_format* format, BAutolock _(fStreamLock); - fPacket.stream_index = fFormatContext->nb_streams; + fPacket->stream_index = fFormatContext->nb_streams; fStream = avformat_new_stream(fFormatContext, NULL); if (fStream == NULL) { @@ -113,7 +114,7 @@ AVFormatWriter::StreamCookie::Init(media_format* format, return B_ERROR; } - fStream->id = fPacket.stream_index; + fStream->id = fPacket->stream_index; // TRACE(" fStream->codecpar: %p\n", fStream->codecpar); // TODO: This is a hack for now! Use avcodec_find_encoder_by_name() @@ -302,21 +303,21 @@ AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer, BAutolock _(fStreamLock); - fPacket.data = const_cast((const uint8_t*)chunkBuffer); - fPacket.size = chunkSize; - fPacket.stream_index = fStream->index; + fPacket->data = const_cast((const uint8_t*)chunkBuffer); + fPacket->size = chunkSize; + fPacket->stream_index = fStream->index; - fPacket.pts = int64_t((double)encodeInfo->start_time + fPacket->pts = int64_t((double)encodeInfo->start_time * fStream->time_base.den / (1000000.0 * fStream->time_base.num) + 0.5); - fPacket.dts = fPacket.pts; + fPacket->dts = fPacket->pts; - fPacket.flags = 0; + fPacket->flags = 0; if ((encodeInfo->flags & B_MEDIA_KEY_FRAME) != 0) - fPacket.flags |= AV_PKT_FLAG_KEY; + fPacket->flags |= AV_PKT_FLAG_KEY; - TRACE_PACKET(" PTS: %" PRId64 " (stream->time_base: (%d/%d)\n", fPacket.pts, + TRACE_PACKET(" PTS: %" PRId64 " (stream->time_base: (%d/%d)\n", fPacket->pts, fStream->time_base.num, fStream->time_base.den); #if 0 @@ -325,11 +326,11 @@ AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer, // more than one stream. For the moment, this crashes in AVPacket // shuffling inside libavformat. Maybe if we want to use this, we // need to allocate a separate AVPacket and copy the chunk buffer. - int result = av_interleaved_write_frame(fFormatContext, &fPacket); + int result = av_interleaved_write_frame(fFormatContext, fPacket); if (result < 0) TRACE(" av_interleaved_write_frame(): %d\n", result); #else - int result = av_write_frame(fFormatContext, &fPacket); + int result = av_write_frame(fFormatContext, fPacket); if (result < 0) TRACE(" av_write_frame(): %d\n", result); #endif