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(base::File file) : file_(file.Pass()) {
     25 }
     26 
     27 MediaFileChecker::~MediaFileChecker() {
     28 }
     29 
     30 bool 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