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_parser_h264.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/logging.h"
      9 #include "base/numerics/safe_conversions.h"
     10 #include "media/base/buffers.h"
     11 #include "media/base/stream_parser_buffer.h"
     12 #include "media/base/video_frame.h"
     13 #include "media/filters/h264_parser.h"
     14 #include "media/formats/common/offset_byte_queue.h"
     15 #include "media/formats/mp2t/es_adapter_video.h"
     16 #include "media/formats/mp2t/mp2t_common.h"
     17 #include "ui/gfx/rect.h"
     18 #include "ui/gfx/size.h"
     19 
     20 namespace media {
     21 namespace mp2t {
     22 
     23 // An AUD NALU is at least 4 bytes:
     24 // 3 bytes for the start code + 1 byte for the NALU type.
     25 const int kMinAUDSize = 4;
     26 
     27 EsParserH264::EsParserH264(
     28     const NewVideoConfigCB& new_video_config_cb,
     29     const EmitBufferCB& emit_buffer_cb)
     30     : es_adapter_(new_video_config_cb, emit_buffer_cb),
     31       h264_parser_(new H264Parser()),
     32       current_access_unit_pos_(0),
     33       next_access_unit_pos_(0) {
     34 }
     35 
     36 EsParserH264::~EsParserH264() {
     37 }
     38 
     39 void EsParserH264::Flush() {
     40   DVLOG(1) << __FUNCTION__;
     41   if (!FindAUD(&current_access_unit_pos_))
     42     return;
     43 
     44   // Simulate an additional AUD to force emitting the last access unit
     45   // which is assumed to be complete at this point.
     46   uint8 aud[] = { 0x00, 0x00, 0x01, 0x09 };
     47   es_queue_->Push(aud, sizeof(aud));
     48   ParseFromEsQueue();
     49 
     50   es_adapter_.Flush();
     51 }
     52 
     53 void EsParserH264::ResetInternal() {
     54   DVLOG(1) << __FUNCTION__;
     55   h264_parser_.reset(new H264Parser());
     56   current_access_unit_pos_ = 0;
     57   next_access_unit_pos_ = 0;
     58   last_video_decoder_config_ = VideoDecoderConfig();
     59   es_adapter_.Reset();
     60 }
     61 
     62 bool EsParserH264::FindAUD(int64* stream_pos) {
     63   while (true) {
     64     const uint8* es;
     65     int size;
     66     es_queue_->PeekAt(*stream_pos, &es, &size);
     67 
     68     // Find a start code and move the stream to the start code parser position.
     69     off_t start_code_offset;
     70     off_t start_code_size;
     71     bool start_code_found = H264Parser::FindStartCode(
     72         es, size, &start_code_offset, &start_code_size);
     73     *stream_pos += start_code_offset;
     74 
     75     // No H264 start code found or NALU type not available yet.
     76     if (!start_code_found || start_code_offset + start_code_size >= size)
     77       return false;
     78 
     79     // Exit the parser loop when an AUD is found.
     80     // Note: NALU header for an AUD:
     81     // - nal_ref_idc must be 0
     82     // - nal_unit_type must be H264NALU::kAUD
     83     if (es[start_code_offset + start_code_size] == H264NALU::kAUD)
     84       break;
     85 
     86     // The current NALU is not an AUD, skip the start code
     87     // and continue parsing the stream.
     88     *stream_pos += start_code_size;
     89   }
     90 
     91   return true;
     92 }
     93 
     94 bool EsParserH264::ParseFromEsQueue() {
     95   DCHECK_LE(es_queue_->head(), current_access_unit_pos_);
     96   DCHECK_LE(current_access_unit_pos_, next_access_unit_pos_);
     97   DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
     98 
     99   // Find the next AUD located at or after |current_access_unit_pos_|. This is
    100   // needed since initially |current_access_unit_pos_| might not point to
    101   // an AUD.
    102   // Discard all the data before the updated |current_access_unit_pos_|
    103   // since it won't be used again.
    104   bool aud_found = FindAUD(&current_access_unit_pos_);
    105   es_queue_->Trim(current_access_unit_pos_);
    106   if (next_access_unit_pos_ < current_access_unit_pos_)
    107     next_access_unit_pos_ = current_access_unit_pos_;
    108 
    109   // Resume parsing later if no AUD was found.
    110   if (!aud_found)
    111     return true;
    112 
    113   // Find the next AUD to make sure we have a complete access unit.
    114   if (next_access_unit_pos_ < current_access_unit_pos_ + kMinAUDSize) {
    115     next_access_unit_pos_ = current_access_unit_pos_ + kMinAUDSize;
    116     DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
    117   }
    118   if (!FindAUD(&next_access_unit_pos_))
    119     return true;
    120 
    121   // At this point, we know we have a full access unit.
    122   bool is_key_frame = false;
    123   int pps_id_for_access_unit = -1;
    124 
    125   const uint8* es;
    126   int size;
    127   es_queue_->PeekAt(current_access_unit_pos_, &es, &size);
    128   int access_unit_size = base::checked_cast<int, int64>(
    129       next_access_unit_pos_ - current_access_unit_pos_);
    130   DCHECK_LE(access_unit_size, size);
    131   h264_parser_->SetStream(es, access_unit_size);
    132 
    133   while (true) {
    134     bool is_eos = false;
    135     H264NALU nalu;
    136     switch (h264_parser_->AdvanceToNextNALU(&nalu)) {
    137       case H264Parser::kOk:
    138         break;
    139       case H264Parser::kInvalidStream:
    140       case H264Parser::kUnsupportedStream:
    141         return false;
    142       case H264Parser::kEOStream:
    143         is_eos = true;
    144         break;
    145     }
    146     if (is_eos)
    147       break;
    148 
    149     switch (nalu.nal_unit_type) {
    150       case H264NALU::kAUD: {
    151         DVLOG(LOG_LEVEL_ES) << "NALU: AUD";
    152         break;
    153       }
    154       case H264NALU::kSPS: {
    155         DVLOG(LOG_LEVEL_ES) << "NALU: SPS";
    156         int sps_id;
    157         if (h264_parser_->ParseSPS(&sps_id) != H264Parser::kOk)
    158           return false;
    159         break;
    160       }
    161       case H264NALU::kPPS: {
    162         DVLOG(LOG_LEVEL_ES) << "NALU: PPS";
    163         int pps_id;
    164         if (h264_parser_->ParsePPS(&pps_id) != H264Parser::kOk)
    165           return false;
    166         break;
    167       }
    168       case H264NALU::kIDRSlice:
    169       case H264NALU::kNonIDRSlice: {
    170         is_key_frame = (nalu.nal_unit_type == H264NALU::kIDRSlice);
    171         DVLOG(LOG_LEVEL_ES) << "NALU: slice IDR=" << is_key_frame;
    172         H264SliceHeader shdr;
    173         if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
    174           // Only accept an invalid SPS/PPS at the beginning when the stream
    175           // does not necessarily start with an SPS/PPS/IDR.
    176           // TODO(damienv): Should be able to differentiate a missing SPS/PPS
    177           // from a slice header parsing error.
    178           if (last_video_decoder_config_.IsValidConfig())
    179             return false;
    180         } else {
    181           pps_id_for_access_unit = shdr.pic_parameter_set_id;
    182         }
    183         break;
    184       }
    185       default: {
    186         DVLOG(LOG_LEVEL_ES) << "NALU: " << nalu.nal_unit_type;
    187       }
    188     }
    189   }
    190 
    191   // Emit a frame and move the stream to the next AUD position.
    192   RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
    193                    is_key_frame, pps_id_for_access_unit));
    194   current_access_unit_pos_ = next_access_unit_pos_;
    195   es_queue_->Trim(current_access_unit_pos_);
    196 
    197   return true;
    198 }
    199 
    200 bool EsParserH264::EmitFrame(int64 access_unit_pos, int access_unit_size,
    201                              bool is_key_frame, int pps_id) {
    202   // Get the access unit timing info.
    203   TimingDesc current_timing_desc = GetTimingDescriptor(access_unit_pos);
    204   if (current_timing_desc.pts == kNoTimestamp())
    205     return false;
    206 
    207   if (current_timing_desc.dts == kNoDecodeTimestamp()) {
    208     current_timing_desc.dts =
    209         DecodeTimestamp::FromPresentationTime(current_timing_desc.pts);
    210   }
    211 
    212   // Update the video decoder configuration if needed.
    213   const H264PPS* pps = h264_parser_->GetPPS(pps_id);
    214   if (!pps) {
    215     // Only accept an invalid PPS at the beginning when the stream
    216     // does not necessarily start with an SPS/PPS/IDR.
    217     // In this case, the initial frames are conveyed to the upper layer with
    218     // an invalid VideoDecoderConfig and it's up to the upper layer
    219     // to process this kind of frame accordingly.
    220     if (last_video_decoder_config_.IsValidConfig())
    221       return false;
    222   } else {
    223     const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id);
    224     if (!sps)
    225       return false;
    226     RCHECK(UpdateVideoDecoderConfig(sps));
    227   }
    228 
    229   // Emit a frame.
    230   DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_
    231                       << " size=" << access_unit_size;
    232   int es_size;
    233   const uint8* es;
    234   es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
    235   CHECK_GE(es_size, access_unit_size);
    236 
    237   // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
    238   // type and allow multiple video tracks. See https://crbug.com/341581.
    239   scoped_refptr<StreamParserBuffer> stream_parser_buffer =
    240       StreamParserBuffer::CopyFrom(
    241           es,
    242           access_unit_size,
    243           is_key_frame,
    244           DemuxerStream::VIDEO,
    245           0);
    246   stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts);
    247   stream_parser_buffer->set_timestamp(current_timing_desc.pts);
    248   es_adapter_.OnNewBuffer(stream_parser_buffer);
    249   return true;
    250 }
    251 
    252 bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps) {
    253   // Set the SAR to 1 when not specified in the H264 stream.
    254   int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width;
    255   int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height;
    256 
    257   // TODO(damienv): a MAP unit can be either 16 or 32 pixels.
    258   // although it's 16 pixels for progressive non MBAFF frames.
    259   gfx::Size coded_size((sps->pic_width_in_mbs_minus1 + 1) * 16,
    260                        (sps->pic_height_in_map_units_minus1 + 1) * 16);
    261   gfx::Rect visible_rect(
    262       sps->frame_crop_left_offset,
    263       sps->frame_crop_top_offset,
    264       (coded_size.width() - sps->frame_crop_right_offset) -
    265       sps->frame_crop_left_offset,
    266       (coded_size.height() - sps->frame_crop_bottom_offset) -
    267       sps->frame_crop_top_offset);
    268   if (visible_rect.width() <= 0 || visible_rect.height() <= 0)
    269     return false;
    270   gfx::Size natural_size(
    271       (visible_rect.width() * sar_width) / sar_height,
    272       visible_rect.height());
    273   if (natural_size.width() == 0)
    274     return false;
    275 
    276   VideoDecoderConfig video_decoder_config(
    277       kCodecH264,
    278       VIDEO_CODEC_PROFILE_UNKNOWN,
    279       VideoFrame::YV12,
    280       coded_size,
    281       visible_rect,
    282       natural_size,
    283       NULL, 0,
    284       false);
    285 
    286   if (!video_decoder_config.Matches(last_video_decoder_config_)) {
    287     DVLOG(1) << "Profile IDC: " << sps->profile_idc;
    288     DVLOG(1) << "Level IDC: " << sps->level_idc;
    289     DVLOG(1) << "Pic width: " << coded_size.width();
    290     DVLOG(1) << "Pic height: " << coded_size.height();
    291     DVLOG(1) << "log2_max_frame_num_minus4: "
    292              << sps->log2_max_frame_num_minus4;
    293     DVLOG(1) << "SAR: width=" << sps->sar_width
    294              << " height=" << sps->sar_height;
    295     last_video_decoder_config_ = video_decoder_config;
    296     es_adapter_.OnConfigChanged(video_decoder_config);
    297   }
    298 
    299   return true;
    300 }
    301 
    302 }  // namespace mp2t
    303 }  // namespace media
    304