Home | History | Annotate | Download | only in mp2t
      1 // Copyright 2014 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/formats/mp2t/es_adapter_video.h"
      6 
      7 #include "media/base/buffers.h"
      8 #include "media/base/stream_parser_buffer.h"
      9 #include "media/base/video_decoder_config.h"
     10 #include "media/formats/mp2t/mp2t_common.h"
     11 
     12 namespace media {
     13 namespace mp2t {
     14 
     15 // Arbitrary decision about the frame duration when there is no previous
     16 // hint about what could be the frame duration.
     17 static const int kDefaultFrameDurationMs = 40;
     18 
     19 // To calculate the frame duration, we make an assumption
     20 // that the timestamp of the next frame in presentation order
     21 // is no further than 5 frames away in decode order.
     22 // TODO(damienv): the previous assumption should cover most of the practical
     23 // cases. However, the right way to calculate the frame duration would be
     24 // to emulate the H264 dpb bumping process.
     25 static const size_t kHistorySize = 5;
     26 
     27 EsAdapterVideo::EsAdapterVideo(
     28     const NewVideoConfigCB& new_video_config_cb,
     29     const EmitBufferCB& emit_buffer_cb)
     30     : new_video_config_cb_(new_video_config_cb),
     31       emit_buffer_cb_(emit_buffer_cb),
     32       has_valid_config_(false),
     33       has_valid_frame_(false),
     34       last_frame_duration_(
     35           base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs)),
     36       buffer_index_(0) {
     37 }
     38 
     39 EsAdapterVideo::~EsAdapterVideo() {
     40 }
     41 
     42 void EsAdapterVideo::Flush() {
     43   ProcessPendingBuffers(true);
     44 }
     45 
     46 void EsAdapterVideo::Reset() {
     47   has_valid_config_ = false;
     48   has_valid_frame_ = false;
     49 
     50   last_frame_duration_ =
     51       base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs);
     52 
     53   config_list_.clear();
     54   buffer_index_ = 0;
     55   buffer_list_.clear();
     56   emitted_pts_.clear();
     57 
     58   discarded_frames_min_pts_ = base::TimeDelta();
     59   discarded_frames_dts_.clear();
     60 }
     61 
     62 void EsAdapterVideo::OnConfigChanged(
     63     const VideoDecoderConfig& video_decoder_config) {
     64   config_list_.push_back(
     65       ConfigEntry(buffer_index_ + buffer_list_.size(), video_decoder_config));
     66   has_valid_config_ = true;
     67   ProcessPendingBuffers(false);
     68 }
     69 
     70 void EsAdapterVideo::OnNewBuffer(
     71     const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) {
     72   // Discard the incoming frame:
     73   // - if it is not associated with any config,
     74   // - or if only non-key frames have been added to a new segment.
     75   if (!has_valid_config_ ||
     76       (!has_valid_frame_ && !stream_parser_buffer->IsKeyframe())) {
     77     if (discarded_frames_dts_.empty() ||
     78         discarded_frames_min_pts_ > stream_parser_buffer->timestamp()) {
     79       discarded_frames_min_pts_ = stream_parser_buffer->timestamp();
     80     }
     81     discarded_frames_dts_.push_back(
     82         stream_parser_buffer->GetDecodeTimestamp());
     83     return;
     84   }
     85 
     86   has_valid_frame_ = true;
     87 
     88   if (!discarded_frames_dts_.empty())
     89     ReplaceDiscardedFrames(stream_parser_buffer);
     90 
     91   buffer_list_.push_back(stream_parser_buffer);
     92   ProcessPendingBuffers(false);
     93 }
     94 
     95 void EsAdapterVideo::ProcessPendingBuffers(bool flush) {
     96   DCHECK(has_valid_config_);
     97 
     98   while (!buffer_list_.empty() &&
     99          (flush || buffer_list_.size() > kHistorySize)) {
    100     // Signal a config change, just before emitting the corresponding frame.
    101     if (!config_list_.empty() && config_list_.front().first == buffer_index_) {
    102       new_video_config_cb_.Run(config_list_.front().second);
    103       config_list_.pop_front();
    104     }
    105 
    106     scoped_refptr<StreamParserBuffer> buffer = buffer_list_.front();
    107     buffer_list_.pop_front();
    108     buffer_index_++;
    109 
    110     if (buffer->duration() == kNoTimestamp()) {
    111       base::TimeDelta next_frame_pts = GetNextFramePts(buffer->timestamp());
    112       if (next_frame_pts == kNoTimestamp()) {
    113         // This can happen when emitting the very last buffer
    114         // or if the stream do not meet the assumption behind |kHistorySize|.
    115         DVLOG(LOG_LEVEL_ES) << "Using last frame duration: "
    116                             << last_frame_duration_.InMilliseconds();
    117         buffer->set_duration(last_frame_duration_);
    118       } else {
    119         base::TimeDelta duration = next_frame_pts - buffer->timestamp();
    120         DVLOG(LOG_LEVEL_ES) << "Frame duration: " << duration.InMilliseconds();
    121         buffer->set_duration(duration);
    122       }
    123     }
    124 
    125     emitted_pts_.push_back(buffer->timestamp());
    126     if (emitted_pts_.size() > kHistorySize)
    127       emitted_pts_.pop_front();
    128 
    129     last_frame_duration_ = buffer->duration();
    130     emit_buffer_cb_.Run(buffer);
    131   }
    132 }
    133 
    134 base::TimeDelta EsAdapterVideo::GetNextFramePts(base::TimeDelta current_pts) {
    135   base::TimeDelta next_pts = kNoTimestamp();
    136 
    137   // Consider the timestamps of future frames (in decode order).
    138   // Note: the next frame is not enough when the GOP includes some B frames.
    139   for (BufferQueue::const_iterator it = buffer_list_.begin();
    140        it != buffer_list_.end(); ++it) {
    141     if ((*it)->timestamp() < current_pts)
    142       continue;
    143     if (next_pts == kNoTimestamp() || next_pts > (*it)->timestamp())
    144       next_pts = (*it)->timestamp();
    145   }
    146 
    147   // Consider the timestamps of previous frames (in decode order).
    148   // In a simple GOP structure with B frames, the frame next to the last B
    149   // frame (in presentation order) is located before in decode order.
    150   for (std::list<base::TimeDelta>::const_iterator it = emitted_pts_.begin();
    151        it != emitted_pts_.end(); ++it) {
    152     if (*it < current_pts)
    153       continue;
    154     if (next_pts == kNoTimestamp() || next_pts > *it)
    155       next_pts = *it;
    156   }
    157 
    158   return next_pts;
    159 }
    160 
    161 void EsAdapterVideo::ReplaceDiscardedFrames(
    162     const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) {
    163   DCHECK(!discarded_frames_dts_.empty());
    164   DCHECK(stream_parser_buffer->IsKeyframe());
    165 
    166   // PTS is interpolated between the min PTS of discarded frames
    167   // and the PTS of the first valid buffer.
    168   base::TimeDelta pts = discarded_frames_min_pts_;
    169   base::TimeDelta pts_delta =
    170       (stream_parser_buffer->timestamp() - pts) / discarded_frames_dts_.size();
    171 
    172   while (!discarded_frames_dts_.empty()) {
    173     scoped_refptr<StreamParserBuffer> frame =
    174         StreamParserBuffer::CopyFrom(
    175             stream_parser_buffer->data(),
    176             stream_parser_buffer->data_size(),
    177             stream_parser_buffer->IsKeyframe(),
    178             stream_parser_buffer->type(),
    179             stream_parser_buffer->track_id());
    180     frame->SetDecodeTimestamp(discarded_frames_dts_.front());
    181     frame->set_timestamp(pts);
    182     frame->set_duration(pts_delta);
    183     buffer_list_.push_back(frame);
    184     pts += pts_delta;
    185     discarded_frames_dts_.pop_front();
    186   }
    187 }
    188 
    189 }  // namespace mp2t
    190 }  // namespace media
    191