1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/media_file_checker.h"
13 #include "base/functional/bind.h"
14 #include "base/time/time.h"
15 #include "media/ffmpeg/ffmpeg_common.h"
16 #include "media/ffmpeg/ffmpeg_decoding_loop.h"
17 #include "media/ffmpeg/ffmpeg_deleters.h"
18 #include "media/filters/blocking_url_protocol.h"
19 #include "media/filters/ffmpeg_glue.h"
20 #include "media/filters/file_data_source.h"
26 constexpr int64_t kMaxCheckTimeInSeconds = 5;
28 void OnMediaFileCheckerError(bool* called) {
33 std::unique_ptr<AVCodecContext, ScopedPtrAVFreeContext> context;
34 std::unique_ptr<FFmpegDecodingLoop> loop;
39 MediaFileChecker::MediaFileChecker(base::File file) : file_(std::move(file)) {}
41 MediaFileChecker::~MediaFileChecker() = default;
43 bool MediaFileChecker::Start(base::TimeDelta check_time) {
44 media::FileDataSource source;
45 if (!source.Initialize(std::move(file_)))
49 media::BlockingUrlProtocol protocol(
50 &source, base::BindRepeating(&OnMediaFileCheckerError, &read_ok));
51 media::FFmpegGlue glue(&protocol);
52 AVFormatContext* format_context = glue.format_context();
54 if (!glue.OpenContext())
57 if (avformat_find_stream_info(format_context, NULL) < 0)
60 // Remember the codec context for any decodable audio or video streams.
61 bool found_streams = false;
62 std::vector<Decoder> stream_contexts(format_context->nb_streams);
63 for (size_t i = 0; i < format_context->nb_streams; ++i) {
64 AVCodecParameters* cp = format_context->streams[i]->codecpar;
66 if (cp->codec_type == AVMEDIA_TYPE_AUDIO ||
67 cp->codec_type == AVMEDIA_TYPE_VIDEO) {
68 auto context = AVStreamToAVCodecContext(format_context->streams[i]);
71 const AVCodec* codec = avcodec_find_decoder(cp->codec_id);
72 if (codec && avcodec_open2(context.get(), codec, nullptr) >= 0) {
73 auto loop = std::make_unique<FFmpegDecodingLoop>(context.get());
74 stream_contexts[i] = {std::move(context), std::move(loop)};
86 auto do_nothing_cb = base::BindRepeating([](AVFrame*) { return true; });
87 const base::TimeTicks deadline =
88 base::TimeTicks::Now() +
89 std::min(check_time, base::Seconds(kMaxCheckTimeInSeconds));
91 result = av_read_frame(glue.format_context(), &packet);
95 auto& decoder = stream_contexts[packet.stream_index];
97 result = decoder.loop->DecodePacket(&packet, do_nothing_cb) ==
98 FFmpegDecodingLoop::DecodeStatus::kOkay
103 av_packet_unref(&packet);
104 } while (base::TimeTicks::Now() < deadline && read_ok && result >= 0);
106 stream_contexts.clear();
107 return read_ok && (result == AVERROR_EOF || result >= 0);