Index: services/media/framework_ffmpeg/ffmpeg_decoder_base.cc |
diff --git a/services/media/framework_ffmpeg/ffmpeg_decoder_base.cc b/services/media/framework_ffmpeg/ffmpeg_decoder_base.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c0cb980906c7ed8f2d50034181e73c62b93b19bc |
--- /dev/null |
+++ b/services/media/framework_ffmpeg/ffmpeg_decoder_base.cc |
@@ -0,0 +1,97 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/logging.h" |
+#include "services/media/framework_ffmpeg/ffmpeg_decoder_base.h" |
+#include "services/media/framework_ffmpeg/ffmpeg_type_converters.h" |
+ |
+namespace mojo { |
+namespace media { |
+ |
+FfmpegDecoderBase::FfmpegDecoderBase(AvCodecContextPtr av_codec_context) : |
+ av_codec_context_(std::move(av_codec_context)), |
+ av_frame_(av_frame_alloc()) { |
+ DCHECK(av_codec_context); |
+} |
+ |
+FfmpegDecoderBase::~FfmpegDecoderBase() {} |
+ |
+std::unique_ptr<StreamType> FfmpegDecoderBase::output_stream_type() { |
+ return StreamTypeFromAVCodecContext(*av_codec_context_); |
+} |
+ |
+void FfmpegDecoderBase::Flush() { |
+ DCHECK(av_codec_context_); |
+ avcodec_flush_buffers(av_codec_context_.get()); |
+} |
+ |
+bool FfmpegDecoderBase::TransformPacket( |
+ const PacketPtr& input, |
+ bool new_input, |
+ PayloadAllocator* allocator, |
+ PacketPtr* output) { |
+ DCHECK(input); |
+ DCHECK(allocator); |
+ DCHECK(output); |
+ |
+ *output = nullptr; |
+ |
+ if (new_input) { |
+ PrepareInputPacket(input); |
+ } |
+ |
+ bool frame_decoded = false; |
+ int input_bytes_used = Decode(allocator, &frame_decoded); |
+ if (input_bytes_used < 0) { |
+ // Decode failed. |
+ return UnprepareInputPacket(input, output); |
+ } |
+ |
+ if (frame_decoded) { |
+ DCHECK(allocator); |
+ *output = CreateOutputPacket(allocator); |
+ av_frame_unref(av_frame_.get()); |
+ } |
+ |
+ CHECK(input_bytes_used <= av_packet_.size) |
+ << "Ffmpeg decoder read beyond end of packet"; |
+ av_packet_.size -= input_bytes_used; |
+ av_packet_.data += input_bytes_used; |
+ |
+ if (av_packet_.size != 0 || (input->end_of_stream() && frame_decoded)) { |
+ // The input packet is only partially decoded, or it's an end-of-stream |
+ // packet and we're still draining. Let the caller know we want to see the |
+ // input packet again. |
+ return false; |
+ } |
+ |
+ // Used up the whole input packet, and, if we were draining, we're done with |
+ // that too. |
+ return UnprepareInputPacket(input, output); |
+} |
+ |
+void FfmpegDecoderBase::PrepareInputPacket(const PacketPtr& input) { |
+ av_init_packet(&av_packet_); |
+ av_packet_.data = reinterpret_cast<uint8_t*>(input->payload()); |
+ av_packet_.size = input->size(); |
+} |
+ |
+bool FfmpegDecoderBase::UnprepareInputPacket( |
+ const PacketPtr& input, |
+ PacketPtr* output) { |
+ if (input->end_of_stream()) { |
+ // Indicate end of stream. This happens when we're draining for the last |
+ // time, so there should be no output packet yet. |
+ DCHECK(*output == nullptr); |
+ *output = CreateOutputEndOfStreamPacket(); |
+ } |
+ |
+ av_packet_.size = 0; |
+ av_packet_.data = nullptr; |
+ |
+ return true; |
+} |
+ |
+} // namespace media |
+} // namespace mojo |