123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- // Copyright 2018 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 "media/filters/android/video_frame_extractor.h"
- #include "base/android/build_info.h"
- #include "base/bind.h"
- #include "base/threading/thread.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "media/base/android/media_codec_bridge_impl.h"
- #include "media/base/data_source.h"
- #include "media/ffmpeg/ffmpeg_common.h"
- #include "media/filters/blocking_url_protocol.h"
- #include "media/filters/ffmpeg_bitstream_converter.h"
- #include "media/filters/ffmpeg_glue.h"
- #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
- #include "media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.h"
- #endif
- #if BUILDFLAG(USE_PROPRIETARY_CODECS)
- #include "media/base/android/extract_sps_and_pps.h"
- #include "media/filters/ffmpeg_aac_bitstream_converter.h"
- #include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h"
- #endif
- namespace media {
- VideoFrameExtractor::VideoFrameExtractor(DataSource* data_source)
- : data_source_(data_source), video_stream_index_(-1) {}
- VideoFrameExtractor::~VideoFrameExtractor() = default;
- void VideoFrameExtractor::Start(VideoFrameCallback video_frame_callback) {
- video_frame_callback_ = std::move(video_frame_callback);
- protocol_ = std::make_unique<BlockingUrlProtocol>(
- data_source_, base::BindRepeating(&VideoFrameExtractor::OnError,
- weak_factory_.GetWeakPtr()));
- glue_ = std::make_unique<FFmpegGlue>(protocol_.get());
- // This will gradually read media data through |data_source_|.
- if (!glue_->OpenContext()) {
- OnError();
- return;
- }
- // Extract the video stream.
- AVFormatContext* format_context = glue_->format_context();
- for (unsigned int i = 0; i < format_context->nb_streams; ++i) {
- AVStream* stream = format_context->streams[i];
- if (!stream)
- continue;
- const AVCodecParameters* codec_parameters = stream->codecpar;
- const AVMediaType codec_type = codec_parameters->codec_type;
- // Pick the first video stream.
- if (codec_type == AVMEDIA_TYPE_VIDEO) {
- video_stream_ = stream;
- video_stream_index_ = i;
- DCHECK_EQ(video_stream_index_, stream->index);
- break;
- }
- }
- if (!video_stream_) {
- OnError();
- return;
- }
- // Get the config for decoding the video frame later.
- if (!AVStreamToVideoDecoderConfig(video_stream_, &video_config_)) {
- OnError();
- return;
- }
- auto packet = ReadVideoFrame();
- if (!packet) {
- OnError();
- return;
- }
- ConvertPacket(packet.get());
- NotifyComplete(
- std::vector<uint8_t>(packet->data, packet->data + packet->size),
- video_config_);
- }
- void VideoFrameExtractor::ConvertPacket(AVPacket* packet) {
- #if BUILDFLAG(USE_PROPRIETARY_CODECS)
- DCHECK(video_stream_ && video_stream_->codecpar);
- // TODO(xingliu): Create the bitstream converter in an utility function. This
- // logic is shared with FFmpegDemuxer.
- switch (video_stream_->codecpar->codec_id) {
- case AV_CODEC_ID_H264:
- video_config_.SetExtraData(std::vector<uint8_t>());
- bitstream_converter_.reset(
- new FFmpegH264ToAnnexBBitstreamConverter(video_stream_->codecpar));
- break;
- #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
- case AV_CODEC_ID_HEVC:
- bitstream_converter_.reset(
- new FFmpegH265ToAnnexBBitstreamConverter(video_stream_->codecpar));
- break;
- #endif
- case AV_CODEC_ID_AAC:
- bitstream_converter_.reset(
- new FFmpegAACBitstreamConverter(video_stream_->codecpar));
- break;
- default:
- break;
- }
- if (bitstream_converter_)
- bitstream_converter_->ConvertPacket(packet);
- #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
- }
- ScopedAVPacket VideoFrameExtractor::ReadVideoFrame() {
- AVFormatContext* format_context = glue_->format_context();
- auto packet = ScopedAVPacket::Allocate();
- while (av_read_frame(format_context, packet.get()) >= 0) {
- // Skip frames from streams other than video.
- if (packet->stream_index != video_stream_index_)
- continue;
- DCHECK(packet->flags & AV_PKT_FLAG_KEY);
- return packet;
- }
- return {};
- }
- void VideoFrameExtractor::NotifyComplete(std::vector<uint8_t> encoded_frame,
- const VideoDecoderConfig& config) {
- // Return the encoded video key frame.
- DCHECK(video_frame_callback_);
- std::move(video_frame_callback_).Run(true, std::move(encoded_frame), config);
- }
- void VideoFrameExtractor::OnError() {
- DCHECK(video_frame_callback_);
- std::move(video_frame_callback_)
- .Run(false, std::vector<uint8_t>(), VideoDecoderConfig());
- }
- } // namespace media
|