LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/common_video/h264 - sps_vui_rewriter.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 125 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  *
      10             :  */
      11             : 
      12             : #include "webrtc/common_video/h264/sps_vui_rewriter.h"
      13             : 
      14             : #include <algorithm>
      15             : #include <memory>
      16             : 
      17             : #include "webrtc/base/bitbuffer.h"
      18             : #include "webrtc/base/checks.h"
      19             : #include "webrtc/base/logging.h"
      20             : 
      21             : #include "webrtc/common_video/h264/h264_common.h"
      22             : #include "webrtc/common_video/h264/sps_parser.h"
      23             : 
      24             : namespace webrtc {
      25             : 
      26             : // The maximum expected growth from adding a VUI to the SPS. It's actually
      27             : // closer to 24 or so, but better safe than sorry.
      28             : const size_t kMaxVuiSpsIncrease = 64;
      29             : 
      30             : #define RETURN_FALSE_ON_FAIL(x)                                  \
      31             :   if (!(x)) {                                                    \
      32             :     LOG_F(LS_ERROR) << " (line:" << __LINE__ << ") FAILED: " #x; \
      33             :     return false;                                                \
      34             :   }
      35             : 
      36             : #define COPY_UINT8(src, dest, tmp)                   \
      37             :   do {                                               \
      38             :     RETURN_FALSE_ON_FAIL((src)->ReadUInt8(&tmp));    \
      39             :     if (dest)                                        \
      40             :       RETURN_FALSE_ON_FAIL((dest)->WriteUInt8(tmp)); \
      41             :   } while (0)
      42             : 
      43             : #define COPY_EXP_GOLOMB(src, dest, tmp)                          \
      44             :   do {                                                           \
      45             :     RETURN_FALSE_ON_FAIL((src)->ReadExponentialGolomb(&tmp));    \
      46             :     if (dest)                                                    \
      47             :       RETURN_FALSE_ON_FAIL((dest)->WriteExponentialGolomb(tmp)); \
      48             :   } while (0)
      49             : 
      50             : #define COPY_BITS(src, dest, tmp, bits)                   \
      51             :   do {                                                    \
      52             :     RETURN_FALSE_ON_FAIL((src)->ReadBits(&tmp, bits));    \
      53             :     if (dest)                                             \
      54             :       RETURN_FALSE_ON_FAIL((dest)->WriteBits(tmp, bits)); \
      55             :   } while (0)
      56             : 
      57             : typedef const SpsParser::SpsState& Sps;
      58             : 
      59             : bool CopyAndRewriteVui(Sps sps,
      60             :                        rtc::BitBuffer* source,
      61             :                        rtc::BitBufferWriter* destination,
      62             :                        SpsVuiRewriter::ParseResult* out_vui_rewritten);
      63             : bool CopyHrdParameters(rtc::BitBuffer* source,
      64             :                        rtc::BitBufferWriter* destination);
      65             : bool AddBitstreamRestriction(rtc::BitBufferWriter* destination,
      66             :                              uint32_t max_num_ref_frames);
      67             : bool CopyRemainingBits(rtc::BitBuffer* source,
      68             :                        rtc::BitBufferWriter* destination);
      69             : 
      70           0 : SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
      71             :     const uint8_t* buffer,
      72             :     size_t length,
      73             :     rtc::Optional<SpsParser::SpsState>* sps,
      74             :     rtc::Buffer* destination) {
      75             :   // Create temporary RBSP decoded buffer of the payload (exlcuding the
      76             :   // leading nalu type header byte (the SpsParser uses only the payload).
      77           0 :   std::unique_ptr<rtc::Buffer> rbsp_buffer = H264::ParseRbsp(buffer, length);
      78           0 :   rtc::BitBuffer source_buffer(rbsp_buffer->data(), rbsp_buffer->size());
      79             :   rtc::Optional<SpsParser::SpsState> sps_state =
      80           0 :       SpsParser::ParseSpsUpToVui(&source_buffer);
      81           0 :   if (!sps_state)
      82           0 :     return ParseResult::kFailure;
      83             : 
      84           0 :   *sps = sps_state;
      85             : 
      86           0 :   if (sps_state->pic_order_cnt_type >= 2) {
      87             :     // No need to rewrite VUI in this case.
      88           0 :     return ParseResult::kPocOk;
      89             :   }
      90             : 
      91             :   // We're going to completely muck up alignment, so we need a BitBuffer to
      92             :   // write with.
      93           0 :   rtc::Buffer out_buffer(length + kMaxVuiSpsIncrease);
      94           0 :   rtc::BitBufferWriter sps_writer(out_buffer.data(), out_buffer.size());
      95             : 
      96             :   // Check how far the SpsParser has read, and copy that data in bulk.
      97             :   size_t byte_offset;
      98             :   size_t bit_offset;
      99           0 :   source_buffer.GetCurrentOffset(&byte_offset, &bit_offset);
     100           0 :   memcpy(out_buffer.data(), rbsp_buffer->data(),
     101           0 :          byte_offset + (bit_offset > 0 ? 1 : 0));  // OK to copy the last bits.
     102             : 
     103             :   // SpsParser will have read the vui_params_present flag, which we want to
     104             :   // modify, so back off a bit;
     105           0 :   if (bit_offset == 0) {
     106           0 :     --byte_offset;
     107           0 :     bit_offset = 7;
     108             :   } else {
     109           0 :     --bit_offset;
     110             :   }
     111           0 :   sps_writer.Seek(byte_offset, bit_offset);
     112             : 
     113             :   ParseResult vui_updated;
     114           0 :   if (!CopyAndRewriteVui(*sps_state, &source_buffer, &sps_writer,
     115             :                          &vui_updated)) {
     116           0 :     LOG(LS_ERROR) << "Failed to parse/copy SPS VUI.";
     117           0 :     return ParseResult::kFailure;
     118             :   }
     119             : 
     120           0 :   if (vui_updated == ParseResult::kVuiOk) {
     121             :     // No update necessary after all, just return.
     122           0 :     return vui_updated;
     123             :   }
     124             : 
     125           0 :   if (!CopyRemainingBits(&source_buffer, &sps_writer)) {
     126           0 :     LOG(LS_ERROR) << "Failed to parse/copy SPS VUI.";
     127           0 :     return ParseResult::kFailure;
     128             :   }
     129             : 
     130             :   // Pad up to next byte with zero bits.
     131           0 :   sps_writer.GetCurrentOffset(&byte_offset, &bit_offset);
     132           0 :   if (bit_offset > 0) {
     133           0 :     sps_writer.WriteBits(0, 8 - bit_offset);
     134           0 :     ++byte_offset;
     135           0 :     bit_offset = 0;
     136             :   }
     137             : 
     138           0 :   RTC_DCHECK(byte_offset <= length + kMaxVuiSpsIncrease);
     139           0 :   RTC_CHECK(destination != nullptr);
     140             : 
     141           0 :   out_buffer.SetSize(byte_offset);
     142             : 
     143             :   // Write updates SPS to destination with added RBSP
     144           0 :   H264::WriteRbsp(out_buffer.data(), out_buffer.size(), destination);
     145             : 
     146           0 :   return ParseResult::kVuiRewritten;
     147             : }
     148             : 
     149           0 : bool CopyAndRewriteVui(Sps sps,
     150             :                        rtc::BitBuffer* source,
     151             :                        rtc::BitBufferWriter* destination,
     152             :                        SpsVuiRewriter::ParseResult* out_vui_rewritten) {
     153             :   uint32_t golomb_tmp;
     154             :   uint32_t bits_tmp;
     155             : 
     156             :   //
     157             :   // vui_parameters_present_flag: u(1)
     158             :   //
     159           0 :   RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
     160             : 
     161             :   // ********* IMPORTANT! **********
     162             :   // Now we're at the VUI, so we want to (1) add it if it isn't present, and
     163             :   // (2) rewrite frame reordering values so no reordering is allowed.
     164           0 :   if (!sps.vui_params_present) {
     165             :     // Write a simple VUI with the parameters we want and 0 for all other flags.
     166             :     // There are 8 flags to be off before the bitstream restriction flag.
     167           0 :     RETURN_FALSE_ON_FAIL(destination->WriteBits(0, 8));
     168             :     // bitstream_restriction_flag: u(1)
     169           0 :     RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
     170           0 :     RETURN_FALSE_ON_FAIL(
     171             :         AddBitstreamRestriction(destination, sps.max_num_ref_frames));
     172             :   } else {
     173             :     // Parse out the full VUI.
     174             :     // aspect_ratio_info_present_flag: u(1)
     175           0 :     COPY_BITS(source, destination, bits_tmp, 1);
     176           0 :     if (bits_tmp == 1) {
     177             :       // aspect_ratio_idc: u(8)
     178           0 :       COPY_BITS(source, destination, bits_tmp, 8);
     179           0 :       if (bits_tmp == 255u) {  // Extended_SAR
     180             :         // sar_width/sar_height: u(16) each.
     181           0 :         COPY_BITS(source, destination, bits_tmp, 32);
     182             :       }
     183             :     }
     184             :     // overscan_info_present_flag: u(1)
     185           0 :     COPY_BITS(source, destination, bits_tmp, 1);
     186           0 :     if (bits_tmp == 1) {
     187             :       // overscan_appropriate_flag: u(1)
     188           0 :       COPY_BITS(source, destination, bits_tmp, 1);
     189             :     }
     190             :     // video_signal_type_present_flag: u(1)
     191           0 :     COPY_BITS(source, destination, bits_tmp, 1);
     192           0 :     if (bits_tmp == 1) {
     193             :       // video_format + video_full_range_flag: u(3) + u(1)
     194           0 :       COPY_BITS(source, destination, bits_tmp, 4);
     195             :       // colour_description_present_flag: u(1)
     196           0 :       COPY_BITS(source, destination, bits_tmp, 1);
     197           0 :       if (bits_tmp == 1) {
     198             :         // colour_primaries, transfer_characteristics, matrix_coefficients:
     199             :         // u(8) each.
     200           0 :         COPY_BITS(source, destination, bits_tmp, 24);
     201             :       }
     202             :     }
     203             :     // chroma_loc_info_present_flag: u(1)
     204           0 :     COPY_BITS(source, destination, bits_tmp, 1);
     205           0 :     if (bits_tmp == 1) {
     206             :       // chroma_sample_loc_type_(top|bottom)_field: ue(v) each.
     207           0 :       COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     208           0 :       COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     209             :     }
     210             :     // timing_info_present_flag: u(1)
     211           0 :     COPY_BITS(source, destination, bits_tmp, 1);
     212           0 :     if (bits_tmp == 1) {
     213             :       // num_units_in_tick, time_scale: u(32) each
     214           0 :       COPY_BITS(source, destination, bits_tmp, 32);
     215           0 :       COPY_BITS(source, destination, bits_tmp, 32);
     216             :       // fixed_frame_rate_flag: u(1)
     217           0 :       COPY_BITS(source, destination, bits_tmp, 1);
     218             :     }
     219             :     // nal_hrd_parameters_present_flag: u(1)
     220             :     uint32_t nal_hrd_parameters_present_flag;
     221           0 :     COPY_BITS(source, destination, nal_hrd_parameters_present_flag, 1);
     222           0 :     if (nal_hrd_parameters_present_flag == 1) {
     223           0 :       RETURN_FALSE_ON_FAIL(CopyHrdParameters(source, destination));
     224             :     }
     225             :     // vcl_hrd_parameters_present_flag: u(1)
     226             :     uint32_t vcl_hrd_parameters_present_flag;
     227           0 :     COPY_BITS(source, destination, vcl_hrd_parameters_present_flag, 1);
     228           0 :     if (vcl_hrd_parameters_present_flag == 1) {
     229           0 :       RETURN_FALSE_ON_FAIL(CopyHrdParameters(source, destination));
     230             :     }
     231           0 :     if (nal_hrd_parameters_present_flag == 1 ||
     232           0 :         vcl_hrd_parameters_present_flag == 1) {
     233             :       // low_delay_hrd_flag: u(1)
     234           0 :       COPY_BITS(source, destination, bits_tmp, 1);
     235             :     }
     236             :     // pic_struct_present_flag: u(1)
     237           0 :     COPY_BITS(source, destination, bits_tmp, 1);
     238             : 
     239             :     // bitstream_restriction_flag: u(1)
     240             :     uint32_t bitstream_restriction_flag;
     241           0 :     RETURN_FALSE_ON_FAIL(source->ReadBits(&bitstream_restriction_flag, 1));
     242           0 :     RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
     243           0 :     if (bitstream_restriction_flag == 0) {
     244             :       // We're adding one from scratch.
     245           0 :       RETURN_FALSE_ON_FAIL(
     246             :           AddBitstreamRestriction(destination, sps.max_num_ref_frames));
     247             :     } else {
     248             :       // We're replacing.
     249             :       // motion_vectors_over_pic_boundaries_flag: u(1)
     250           0 :       COPY_BITS(source, destination, bits_tmp, 1);
     251             :       // max_bytes_per_pic_denom: ue(v)
     252           0 :       COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     253             :       // max_bits_per_mb_denom: ue(v)
     254           0 :       COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     255             :       // log2_max_mv_length_horizontal: ue(v)
     256           0 :       COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     257             :       // log2_max_mv_length_vertical: ue(v)
     258           0 :       COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     259             :       // ********* IMPORTANT! **********
     260             :       // The next two are the ones we need to set to low numbers:
     261             :       // max_num_reorder_frames: ue(v)
     262             :       // max_dec_frame_buffering: ue(v)
     263             :       // However, if they are already set to no greater than the numbers we
     264             :       // want, then we don't need to be rewriting.
     265             :       uint32_t max_num_reorder_frames, max_dec_frame_buffering;
     266           0 :       RETURN_FALSE_ON_FAIL(
     267             :           source->ReadExponentialGolomb(&max_num_reorder_frames));
     268           0 :       RETURN_FALSE_ON_FAIL(
     269             :           source->ReadExponentialGolomb(&max_dec_frame_buffering));
     270           0 :       if (max_num_reorder_frames == 0 &&
     271           0 :           max_dec_frame_buffering <= sps.max_num_ref_frames) {
     272           0 :         LOG(LS_INFO) << "VUI bitstream already contains an optimal VUI.";
     273           0 :         *out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiOk;
     274           0 :         return true;
     275             :       }
     276           0 :       RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(0));
     277           0 :       RETURN_FALSE_ON_FAIL(
     278             :           destination->WriteExponentialGolomb(sps.max_num_ref_frames));
     279             :     }
     280             :   }
     281           0 :   *out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiRewritten;
     282           0 :   return true;
     283             : }
     284             : 
     285             : // Copies a VUI HRD parameters segment.
     286           0 : bool CopyHrdParameters(rtc::BitBuffer* source,
     287             :                        rtc::BitBufferWriter* destination) {
     288             :   uint32_t golomb_tmp;
     289             :   uint32_t bits_tmp;
     290             : 
     291             :   // cbp_cnt_minus1: ue(v)
     292             :   uint32_t cbp_cnt_minus1;
     293           0 :   COPY_EXP_GOLOMB(source, destination, cbp_cnt_minus1);
     294             :   // bit_rate_scale and cbp_size_scale: u(4) each
     295           0 :   COPY_BITS(source, destination, bits_tmp, 8);
     296           0 :   for (size_t i = 0; i <= cbp_cnt_minus1; ++i) {
     297             :     // bit_rate_value_minus1 and cbp_size_value_minus1: ue(v) each
     298           0 :     COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     299           0 :     COPY_EXP_GOLOMB(source, destination, golomb_tmp);
     300             :     // cbr_flag: u(1)
     301           0 :     COPY_BITS(source, destination, bits_tmp, 1);
     302             :   }
     303             :   // initial_cbp_removal_delay_length_minus1: u(5)
     304           0 :   COPY_BITS(source, destination, bits_tmp, 5);
     305             :   // cbp_removal_delay_length_minus1: u(5)
     306           0 :   COPY_BITS(source, destination, bits_tmp, 5);
     307             :   // dbp_output_delay_length_minus1: u(5)
     308           0 :   COPY_BITS(source, destination, bits_tmp, 5);
     309             :   // time_offset_length: u(5)
     310           0 :   COPY_BITS(source, destination, bits_tmp, 5);
     311           0 :   return true;
     312             : }
     313             : 
     314             : // These functions are similar to webrtc::H264SpsParser::Parse, and based on the
     315             : // same version of the H.264 standard. You can find it here:
     316             : // http://www.itu.int/rec/T-REC-H.264
     317             : 
     318             : // Adds a bitstream restriction VUI segment.
     319           0 : bool AddBitstreamRestriction(rtc::BitBufferWriter* destination,
     320             :                              uint32_t max_num_ref_frames) {
     321             :   // motion_vectors_over_pic_boundaries_flag: u(1)
     322             :   // Default is 1 when not present.
     323           0 :   RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1));
     324             :   // max_bytes_per_pic_denom: ue(v)
     325             :   // Default is 2 when not present.
     326           0 :   RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(2));
     327             :   // max_bits_per_mb_denom: ue(v)
     328             :   // Default is 1 when not present.
     329           0 :   RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(1));
     330             :   // log2_max_mv_length_horizontal: ue(v)
     331             :   // log2_max_mv_length_vertical: ue(v)
     332             :   // Both default to 16 when not present.
     333           0 :   RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16));
     334           0 :   RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16));
     335             : 
     336             :   // ********* IMPORTANT! **********
     337             :   // max_num_reorder_frames: ue(v)
     338           0 :   RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(0));
     339             :   // max_dec_frame_buffering: ue(v)
     340           0 :   RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(max_num_ref_frames));
     341           0 :   return true;
     342             : }
     343             : 
     344           0 : bool CopyRemainingBits(rtc::BitBuffer* source,
     345             :                        rtc::BitBufferWriter* destination) {
     346             :   uint32_t bits_tmp;
     347             :   // Try to get at least the destination aligned.
     348           0 :   if (source->RemainingBitCount() > 0 && source->RemainingBitCount() % 8 != 0) {
     349           0 :     size_t misaligned_bits = source->RemainingBitCount() % 8;
     350           0 :     COPY_BITS(source, destination, bits_tmp, misaligned_bits);
     351             :   }
     352           0 :   while (source->RemainingBitCount() > 0) {
     353             :     size_t count = std::min(static_cast<size_t>(32u),
     354           0 :                             static_cast<size_t>(source->RemainingBitCount()));
     355           0 :     COPY_BITS(source, destination, bits_tmp, count);
     356             :   }
     357             :   // TODO(noahric): The last byte could be all zeroes now, which we should just
     358             :   // strip.
     359           0 :   return true;
     360             : }
     361             : 
     362             : }  // namespace webrtc

Generated by: LCOV version 1.13