[M120 Migration][hbbtv] Audio tracks count notification
[platform/framework/web/chromium-efl.git] / media / filters / media_file_checker.cc
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.
4
5 #include "media/filters/media_file_checker.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <map>
10 #include <memory>
11 #include <utility>
12
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"
21
22 namespace media {
23
24 namespace {
25
26 constexpr int64_t kMaxCheckTimeInSeconds = 5;
27
28 void OnMediaFileCheckerError(bool* called) {
29   *called = false;
30 }
31
32 struct Decoder {
33   std::unique_ptr<AVCodecContext, ScopedPtrAVFreeContext> context;
34   std::unique_ptr<FFmpegDecodingLoop> loop;
35 };
36
37 }  // namespace
38
39 MediaFileChecker::MediaFileChecker(base::File file) : file_(std::move(file)) {}
40
41 MediaFileChecker::~MediaFileChecker() = default;
42
43 bool MediaFileChecker::Start(base::TimeDelta check_time) {
44   media::FileDataSource source;
45   if (!source.Initialize(std::move(file_)))
46     return false;
47
48   bool read_ok = true;
49   media::BlockingUrlProtocol protocol(
50       &source, base::BindRepeating(&OnMediaFileCheckerError, &read_ok));
51   media::FFmpegGlue glue(&protocol);
52   AVFormatContext* format_context = glue.format_context();
53
54   if (!glue.OpenContext())
55     return false;
56
57   if (avformat_find_stream_info(format_context, NULL) < 0)
58     return false;
59
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;
65
66     if (cp->codec_type == AVMEDIA_TYPE_AUDIO ||
67         cp->codec_type == AVMEDIA_TYPE_VIDEO) {
68       auto context = AVStreamToAVCodecContext(format_context->streams[i]);
69       if (!context)
70         continue;
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)};
75         found_streams = true;
76       }
77     }
78   }
79
80   if (!found_streams)
81     return false;
82
83   AVPacket packet;
84   int result = 0;
85
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));
90   do {
91     result = av_read_frame(glue.format_context(), &packet);
92     if (result < 0)
93       break;
94
95     auto& decoder = stream_contexts[packet.stream_index];
96     if (decoder.loop) {
97       result = decoder.loop->DecodePacket(&packet, do_nothing_cb) ==
98                        FFmpegDecodingLoop::DecodeStatus::kOkay
99                    ? 0
100                    : -1;
101     }
102
103     av_packet_unref(&packet);
104   } while (base::TimeTicks::Now() < deadline && read_ok && result >= 0);
105
106   stream_contexts.clear();
107   return read_ok && (result == AVERROR_EOF || result >= 0);
108 }
109
110 }  // namespace media