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_malloc
<AVFrame
, media::ScopedPtrAVFreeFrame
> frame(
63 const base::TimeTicks deadline
= base::TimeTicks::Now() +
65 base::TimeDelta::FromSeconds(kMaxCheckTimeInSeconds
));
67 result
= av_read_frame(glue
.format_context(), &packet
);
70 result
= av_dup_packet(&packet
);
74 std::map
<int, AVCodecContext
*>::const_iterator it
=
75 stream_contexts
.find(packet
.stream_index
);
76 if (it
== stream_contexts
.end()) {
77 av_free_packet(&packet
);
80 AVCodecContext
* av_context
= it
->second
;
82 int frame_decoded
= 0;
83 if (av_context
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
84 // A shallow copy of packet so we can slide packet.data as frames are
85 // decoded; otherwise av_free_packet() will corrupt memory.
86 AVPacket temp_packet
= packet
;
88 avcodec_get_frame_defaults(frame
.get());
89 result
= avcodec_decode_audio4(av_context
, frame
.get(), &frame_decoded
,
93 temp_packet
.size
-= result
;
94 temp_packet
.data
+= result
;
95 } while (temp_packet
.size
> 0);
96 } else if (av_context
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
97 avcodec_get_frame_defaults(frame
.get());
98 result
= avcodec_decode_video2(av_context
, frame
.get(), &frame_decoded
,
101 av_free_packet(&packet
);
102 } while (base::TimeTicks::Now() < deadline
&& read_ok
&& result
>= 0);
104 return read_ok
&& (result
== AVERROR_EOF
|| result
>= 0);