1 // Copyright 2013 The Chromium Authors. All rights reserved.
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/base/media_file_checker.h"
10 #include "base/time/time.h"
11 #include "media/ffmpeg/ffmpeg_common.h"
12 #include "media/filters/blocking_url_protocol.h"
13 #include "media/filters/ffmpeg_glue.h"
14 #include "media/filters/file_data_source.h"
18 static const int64 kMaxCheckTimeInSeconds
= 5;
20 static void OnError(bool* called
) {
24 MediaFileChecker::MediaFileChecker(base::File file
) : file_(file
.Pass()) {
27 MediaFileChecker::~MediaFileChecker() {
30 bool MediaFileChecker::Start(base::TimeDelta check_time
) {
31 media::FileDataSource
source(file_
.Pass());
33 media::BlockingUrlProtocol
protocol(&source
, base::Bind(&OnError
, &read_ok
));
34 media::FFmpegGlue
glue(&protocol
);
35 AVFormatContext
* format_context
= glue
.format_context();
37 if (!glue
.OpenContext())
40 if (avformat_find_stream_info(format_context
, NULL
) < 0)
43 // Remember the codec context for any decodable audio or video streams.
44 std::map
<int, AVCodecContext
*> stream_contexts
;
45 for (size_t i
= 0; i
< format_context
->nb_streams
; ++i
) {
46 AVCodecContext
* c
= format_context
->streams
[i
]->codec
;
47 if (c
->codec_type
== AVMEDIA_TYPE_AUDIO
||
48 c
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
49 AVCodec
* codec
= avcodec_find_decoder(c
->codec_id
);
50 if (codec
&& avcodec_open2(c
, codec
, NULL
) >= 0)
51 stream_contexts
[i
] = c
;
55 if (stream_contexts
.size() == 0)
59 scoped_ptr
<AVFrame
, media::ScopedPtrAVFreeFrame
> frame(av_frame_alloc());
62 const base::TimeTicks deadline
= base::TimeTicks::Now() +
64 base::TimeDelta::FromSeconds(kMaxCheckTimeInSeconds
));
66 result
= av_read_frame(glue
.format_context(), &packet
);
69 result
= av_dup_packet(&packet
);
73 std::map
<int, AVCodecContext
*>::const_iterator it
=
74 stream_contexts
.find(packet
.stream_index
);
75 if (it
== stream_contexts
.end()) {
76 av_free_packet(&packet
);
79 AVCodecContext
* av_context
= it
->second
;
81 int frame_decoded
= 0;
82 if (av_context
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
83 // A shallow copy of packet so we can slide packet.data as frames are
84 // decoded; otherwise av_free_packet() will corrupt memory.
85 AVPacket temp_packet
= packet
;
87 result
= avcodec_decode_audio4(av_context
, frame
.get(), &frame_decoded
,
91 av_frame_unref(frame
.get());
92 temp_packet
.size
-= result
;
93 temp_packet
.data
+= result
;
95 } while (temp_packet
.size
> 0);
96 } else if (av_context
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
97 result
= avcodec_decode_video2(av_context
, frame
.get(), &frame_decoded
,
99 if (result
>= 0 && frame_decoded
)
100 av_frame_unref(frame
.get());
102 av_free_packet(&packet
);
103 } while (base::TimeTicks::Now() < deadline
&& read_ok
&& result
>= 0);
105 return read_ok
&& (result
== AVERROR_EOF
|| result
>= 0);