1ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// found in the LICENSE file. 4ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 5ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "media/base/media_file_checker.h" 6ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 7ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <map> 8ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 9ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/bind.h" 10ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/time/time.h" 11ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "media/ffmpeg/ffmpeg_common.h" 12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "media/filters/blocking_url_protocol.h" 13ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "media/filters/ffmpeg_glue.h" 14ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "media/filters/file_data_source.h" 15ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 16ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochnamespace media { 17ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 18ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochstatic const int64 kMaxCheckTimeInSeconds = 5; 19ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 20ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochstatic void OnError(bool* called) { 21ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch *called = false; 22ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 23ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 24ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochMediaFileChecker::MediaFileChecker(const base::PlatformFile& file) 25ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch : file_(file), 26ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch file_closer_(&file_) { 27ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 28ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 29ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochMediaFileChecker::~MediaFileChecker() { 30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 31ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 32ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool MediaFileChecker::Start(base::TimeDelta check_time) { 33ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch media::FileDataSource source; 34ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch bool read_ok = true; 35ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch media::BlockingUrlProtocol protocol(&source, base::Bind(&OnError, &read_ok)); 36ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch media::FFmpegGlue glue(&protocol); 37ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch source.InitializeFromPlatformFile(file_); 38ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AVFormatContext* format_context = glue.format_context(); 39ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 40ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!glue.OpenContext()) 41ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return false; 42ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 43ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (avformat_find_stream_info(format_context, NULL) < 0) 44ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return false; 45ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 46ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Remember the codec context for any decodable audio or video streams. 47ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::map<int, AVCodecContext*> stream_contexts; 48ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch for (size_t i = 0; i < format_context->nb_streams; ++i) { 49ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AVCodecContext* c = format_context->streams[i]->codec; 50ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (c->codec_type == AVMEDIA_TYPE_AUDIO || 51ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch c->codec_type == AVMEDIA_TYPE_VIDEO) { 52ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AVCodec* codec = avcodec_find_decoder(c->codec_id); 53ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (codec && avcodec_open2(c, codec, NULL) >= 0) 54ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch stream_contexts[i] = c; 55ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 56ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (stream_contexts.size() == 0) 59ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return false; 60ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 61ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AVPacket packet; 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr_malloc<AVFrame, media::ScopedPtrAVFreeFrame> frame( 63d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) av_frame_alloc()); 64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch int result = 0; 65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch base::Time deadline = base::Time::Now() + 67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::min(check_time, 68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch base::TimeDelta::FromSeconds(kMaxCheckTimeInSeconds)); 69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch do { 70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch result = av_read_frame(glue.format_context(), &packet); 71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (result < 0) 72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch break; 73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch result = av_dup_packet(&packet); 74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (result < 0) 75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch break; 76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 77ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::map<int, AVCodecContext*>::const_iterator it = 78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch stream_contexts.find(packet.stream_index); 79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (it == stream_contexts.end()) { 80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch av_free_packet(&packet); 81ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch continue; 82ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 83ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AVCodecContext* av_context = it->second; 84ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 85ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch int frame_decoded = 0; 86ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (av_context->codec_type == AVMEDIA_TYPE_AUDIO) { 87ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // A shallow copy of packet so we can slide packet.data as frames are 88ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // decoded; otherwise av_free_packet() will corrupt memory. 89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch AVPacket temp_packet = packet; 90ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch do { 91ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch avcodec_get_frame_defaults(frame.get()); 92ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch result = avcodec_decode_audio4(av_context, frame.get(), &frame_decoded, 93ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch &temp_packet); 94ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (result < 0) 95ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch break; 96ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch temp_packet.size -= result; 97ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch temp_packet.data += result; 98ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } while (temp_packet.size > 0); 99ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } else if (av_context->codec_type == AVMEDIA_TYPE_VIDEO) { 100ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch avcodec_get_frame_defaults(frame.get()); 101ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch result = avcodec_decode_video2(av_context, frame.get(), &frame_decoded, 102ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch &packet); 103ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 104ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch av_free_packet(&packet); 105ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } while (base::Time::Now() < deadline && read_ok && result >= 0); 106ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 107ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return read_ok && (result == AVERROR_EOF || result >= 0); 108ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 109ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 110ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} // namespace media 111