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. 4 5#include "media/base/media_file_checker.h" 6 7#include <map> 8 9#include "base/bind.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" 15 16namespace media { 17 18static const int64 kMaxCheckTimeInSeconds = 5; 19 20static void OnError(bool* called) { 21 *called = false; 22} 23 24MediaFileChecker::MediaFileChecker(base::File file) : file_(file.Pass()) { 25} 26 27MediaFileChecker::~MediaFileChecker() { 28} 29 30bool MediaFileChecker::Start(base::TimeDelta check_time) { 31 media::FileDataSource source(file_.Pass()); 32 bool read_ok = true; 33 media::BlockingUrlProtocol protocol(&source, base::Bind(&OnError, &read_ok)); 34 media::FFmpegGlue glue(&protocol); 35 AVFormatContext* format_context = glue.format_context(); 36 37 if (!glue.OpenContext()) 38 return false; 39 40 if (avformat_find_stream_info(format_context, NULL) < 0) 41 return false; 42 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; 52 } 53 } 54 55 if (stream_contexts.size() == 0) 56 return false; 57 58 AVPacket packet; 59 scoped_ptr<AVFrame, media::ScopedPtrAVFreeFrame> frame(av_frame_alloc()); 60 int result = 0; 61 62 const base::TimeTicks deadline = base::TimeTicks::Now() + 63 std::min(check_time, 64 base::TimeDelta::FromSeconds(kMaxCheckTimeInSeconds)); 65 do { 66 result = av_read_frame(glue.format_context(), &packet); 67 if (result < 0) 68 break; 69 result = av_dup_packet(&packet); 70 if (result < 0) 71 break; 72 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); 77 continue; 78 } 79 AVCodecContext* av_context = it->second; 80 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; 86 do { 87 result = avcodec_decode_audio4(av_context, frame.get(), &frame_decoded, 88 &temp_packet); 89 if (result < 0) 90 break; 91 av_frame_unref(frame.get()); 92 temp_packet.size -= result; 93 temp_packet.data += result; 94 frame_decoded = 0; 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, 98 &packet); 99 if (result >= 0 && frame_decoded) 100 av_frame_unref(frame.get()); 101 } 102 av_free_packet(&packet); 103 } while (base::TimeTicks::Now() < deadline && read_ok && result >= 0); 104 105 return read_ok && (result == AVERROR_EOF || result >= 0); 106} 107 108} // namespace media 109