Home | History | Annotate | Download | only in base
      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 
     16 namespace media {
     17 
     18 static const int64 kMaxCheckTimeInSeconds = 5;
     19 
     20 static void OnError(bool* called) {
     21   *called = false;
     22 }
     23 
     24 MediaFileChecker::MediaFileChecker(const base::PlatformFile& file)
     25     : file_(file),
     26       file_closer_(&file_) {
     27 }
     28 
     29 MediaFileChecker::~MediaFileChecker() {
     30 }
     31 
     32 bool MediaFileChecker::Start(base::TimeDelta check_time) {
     33   media::FileDataSource source;
     34   bool read_ok = true;
     35   media::BlockingUrlProtocol protocol(&source, base::Bind(&OnError, &read_ok));
     36   media::FFmpegGlue glue(&protocol);
     37   source.InitializeFromPlatformFile(file_);
     38   AVFormatContext* format_context = glue.format_context();
     39 
     40   if (!glue.OpenContext())
     41     return false;
     42 
     43   if (avformat_find_stream_info(format_context, NULL) < 0)
     44     return false;
     45 
     46   // Remember the codec context for any decodable audio or video streams.
     47   std::map<int, AVCodecContext*> stream_contexts;
     48   for (size_t i = 0; i < format_context->nb_streams; ++i) {
     49     AVCodecContext* c = format_context->streams[i]->codec;
     50     if (c->codec_type == AVMEDIA_TYPE_AUDIO ||
     51         c->codec_type == AVMEDIA_TYPE_VIDEO) {
     52       AVCodec* codec = avcodec_find_decoder(c->codec_id);
     53       if (codec && avcodec_open2(c, codec, NULL) >= 0)
     54         stream_contexts[i] = c;
     55     }
     56   }
     57 
     58   if (stream_contexts.size() == 0)
     59     return false;
     60 
     61   AVPacket packet;
     62   scoped_ptr_malloc<AVFrame, media::ScopedPtrAVFree> frame(
     63       avcodec_alloc_frame());
     64   int result = 0;
     65 
     66   base::Time deadline = base::Time::Now() +
     67       std::min(check_time,
     68                base::TimeDelta::FromSeconds(kMaxCheckTimeInSeconds));
     69   do {
     70     result = av_read_frame(glue.format_context(), &packet);
     71     if (result < 0)
     72       break;
     73     result = av_dup_packet(&packet);
     74     if (result < 0)
     75       break;
     76 
     77     std::map<int, AVCodecContext*>::const_iterator it =
     78         stream_contexts.find(packet.stream_index);
     79     if (it == stream_contexts.end()) {
     80       av_free_packet(&packet);
     81       continue;
     82     }
     83     AVCodecContext* av_context = it->second;
     84 
     85     int frame_decoded = 0;
     86     if (av_context->codec_type == AVMEDIA_TYPE_AUDIO) {
     87       // A shallow copy of packet so we can slide packet.data as frames are
     88       // decoded; otherwise av_free_packet() will corrupt memory.
     89       AVPacket temp_packet = packet;
     90       do {
     91         avcodec_get_frame_defaults(frame.get());
     92         result = avcodec_decode_audio4(av_context, frame.get(), &frame_decoded,
     93                                        &temp_packet);
     94         if (result < 0)
     95           break;
     96         temp_packet.size -= result;
     97         temp_packet.data += result;
     98       } while (temp_packet.size > 0);
     99     } else if (av_context->codec_type == AVMEDIA_TYPE_VIDEO) {
    100       avcodec_get_frame_defaults(frame.get());
    101       result = avcodec_decode_video2(av_context, frame.get(), &frame_decoded,
    102                                      &packet);
    103     }
    104     av_free_packet(&packet);
    105   } while (base::Time::Now() < deadline && read_ok && result >= 0);
    106 
    107   return read_ok && (result == AVERROR_EOF || result >= 0);
    108 }
    109 
    110 }  // namespace media
    111