LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/video_coding - h264_sps_pps_tracker.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 107 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 2 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             : #include "webrtc/modules/video_coding/h264_sps_pps_tracker.h"
      12             : 
      13             : #include <string>
      14             : #include <utility>
      15             : 
      16             : #include "webrtc/base/checks.h"
      17             : #include "webrtc/base/logging.h"
      18             : #include "webrtc/common_video/h264/h264_common.h"
      19             : #include "webrtc/common_video/h264/pps_parser.h"
      20             : #include "webrtc/common_video/h264/sps_parser.h"
      21             : #include "webrtc/modules/video_coding/frame_object.h"
      22             : #include "webrtc/modules/video_coding/packet_buffer.h"
      23             : 
      24             : namespace webrtc {
      25             : namespace video_coding {
      26             : 
      27             : namespace {
      28             : const uint8_t start_code_h264[] = {0, 0, 0, 1};
      29             : }  // namespace
      30             : 
      31           0 : H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream(
      32             :     VCMPacket* packet) {
      33           0 :   RTC_DCHECK(packet->codec == kVideoCodecH264);
      34             : 
      35           0 :   const uint8_t* data = packet->dataPtr;
      36           0 :   const size_t data_size = packet->sizeBytes;
      37           0 :   const RTPVideoHeader& video_header = packet->video_header;
      38           0 :   const RTPVideoHeaderH264& codec_header = video_header.codecHeader.H264;
      39             : 
      40             :   // Packets that only contains SPS/PPS are not decodable by themselves, and
      41             :   // to avoid frames being created containing only these two nalus we don't
      42             :   // insert them into the PacketBuffer. Instead we save the SPS/PPS and
      43             :   // prepend the bitstream of first packet of an IDR referring to the
      44             :   // corresponding SPS/PPS id.
      45           0 :   bool insert_packet = codec_header.nalus_length == 0 ? true : false;
      46             : 
      47           0 :   int pps_id = -1;
      48           0 :   size_t required_size = 0;
      49           0 :   for (size_t i = 0; i < codec_header.nalus_length; ++i) {
      50           0 :     const NaluInfo& nalu = codec_header.nalus[i];
      51           0 :     switch (nalu.type) {
      52             :       case H264::NaluType::kSps: {
      53             :         // Save SPS.
      54           0 :         sps_data_[nalu.sps_id].size = nalu.size;
      55           0 :         sps_data_[nalu.sps_id].data.reset(new uint8_t[nalu.size]);
      56           0 :         memcpy(sps_data_[nalu.sps_id].data.get(), data + nalu.offset,
      57           0 :                nalu.size);
      58           0 :         break;
      59             :       }
      60             :       case H264::NaluType::kPps: {
      61             :         // Save PPS.
      62           0 :         pps_data_[nalu.pps_id].sps_id = nalu.sps_id;
      63           0 :         pps_data_[nalu.pps_id].size = nalu.size;
      64           0 :         pps_data_[nalu.pps_id].data.reset(new uint8_t[nalu.size]);
      65           0 :         memcpy(pps_data_[nalu.pps_id].data.get(), data + nalu.offset,
      66           0 :                nalu.size);
      67           0 :         break;
      68             :       }
      69             :       case H264::NaluType::kIdr: {
      70             :         // If this is the first packet of an IDR, make sure we have the required
      71             :         // SPS/PPS and also calculate how much extra space we need in the buffer
      72             :         // to prepend the SPS/PPS to the bitstream with start codes.
      73           0 :         if (video_header.is_first_packet_in_frame) {
      74           0 :           if (nalu.pps_id == -1) {
      75           0 :             LOG(LS_WARNING) << "No PPS id in IDR nalu.";
      76           0 :             return kRequestKeyframe;
      77             :           }
      78             : 
      79           0 :           auto pps = pps_data_.find(nalu.pps_id);
      80           0 :           if (pps == pps_data_.end()) {
      81           0 :             LOG(LS_WARNING) << "No PPS with id << " << nalu.pps_id
      82           0 :                             << " received";
      83           0 :             return kRequestKeyframe;
      84             :           }
      85             : 
      86           0 :           auto sps = sps_data_.find(pps->second.sps_id);
      87           0 :           if (sps == sps_data_.end()) {
      88           0 :             LOG(LS_WARNING) << "No SPS with id << "
      89           0 :                             << pps_data_[nalu.pps_id].sps_id << " received";
      90           0 :             return kRequestKeyframe;
      91             :           }
      92             : 
      93           0 :           pps_id = nalu.pps_id;
      94           0 :           required_size += pps->second.size + sizeof(start_code_h264);
      95           0 :           required_size += sps->second.size + sizeof(start_code_h264);
      96             :         }
      97             :         FALLTHROUGH();
      98             :       }
      99             :       default: {
     100             :         // Something other than an SPS/PPS nalu in this packet, then it should
     101             :         // be inserted into the PacketBuffer.
     102           0 :         insert_packet = true;
     103             :       }
     104             :     }
     105             :   }
     106             : 
     107           0 :   if (!insert_packet)
     108           0 :     return kDrop;
     109             : 
     110             :   // Calculate how much space we need for the rest of the bitstream.
     111           0 :   if (codec_header.packetization_type == kH264StapA) {
     112           0 :     const uint8_t* nalu_ptr = data + 1;
     113           0 :     while (nalu_ptr < data + data_size) {
     114           0 :       RTC_DCHECK(video_header.is_first_packet_in_frame);
     115           0 :       required_size += sizeof(start_code_h264);
     116             : 
     117             :       // The first two bytes describe the length of a segment.
     118           0 :       uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
     119           0 :       nalu_ptr += 2;
     120             : 
     121           0 :       required_size += segment_length;
     122           0 :       nalu_ptr += segment_length;
     123             :     }
     124             :   } else {
     125           0 :     if (video_header.is_first_packet_in_frame)
     126           0 :       required_size += sizeof(start_code_h264);
     127           0 :     required_size += data_size;
     128             :   }
     129             : 
     130             :   // Then we copy to the new buffer.
     131           0 :   uint8_t* buffer = new uint8_t[required_size];
     132           0 :   uint8_t* insert_at = buffer;
     133             : 
     134             :   // If pps_id != -1 then we have the SPS/PPS and they should be prepended
     135             :   // to the bitstream with start codes inserted.
     136           0 :   if (pps_id != -1) {
     137             :     // Insert SPS.
     138           0 :     memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
     139           0 :     insert_at += sizeof(start_code_h264);
     140           0 :     memcpy(insert_at, sps_data_[pps_data_[pps_id].sps_id].data.get(),
     141           0 :            sps_data_[pps_data_[pps_id].sps_id].size);
     142           0 :     insert_at += sps_data_[pps_data_[pps_id].sps_id].size;
     143             : 
     144             :     // Insert PPS.
     145           0 :     memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
     146           0 :     insert_at += sizeof(start_code_h264);
     147           0 :     memcpy(insert_at, pps_data_[pps_id].data.get(), pps_data_[pps_id].size);
     148           0 :     insert_at += pps_data_[pps_id].size;
     149             :   }
     150             : 
     151             :   // Copy the rest of the bitstream and insert start codes.
     152           0 :   if (codec_header.packetization_type == kH264StapA) {
     153           0 :     const uint8_t* nalu_ptr = data + 1;
     154           0 :     while (nalu_ptr < data + data_size) {
     155           0 :       memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
     156           0 :       insert_at += sizeof(start_code_h264);
     157             : 
     158             :       // The first two bytes describe the length of a segment.
     159           0 :       uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
     160           0 :       nalu_ptr += 2;
     161             : 
     162           0 :       size_t copy_end = nalu_ptr - data + segment_length;
     163           0 :       if (copy_end > data_size) {
     164           0 :         delete[] buffer;
     165           0 :         return kDrop;
     166             :       }
     167             : 
     168           0 :       memcpy(insert_at, nalu_ptr, segment_length);
     169           0 :       insert_at += segment_length;
     170           0 :       nalu_ptr += segment_length;
     171             :     }
     172             :   } else {
     173           0 :     if (video_header.is_first_packet_in_frame) {
     174           0 :       memcpy(insert_at, start_code_h264, sizeof(start_code_h264));
     175           0 :       insert_at += sizeof(start_code_h264);
     176             :     }
     177           0 :     memcpy(insert_at, data, data_size);
     178             :   }
     179             : 
     180           0 :   packet->dataPtr = buffer;
     181           0 :   packet->sizeBytes = required_size;
     182           0 :   return kInsert;
     183             : }
     184             : 
     185           0 : void H264SpsPpsTracker::InsertSpsPps(const std::vector<uint8_t>& sps,
     186             :                                      const std::vector<uint8_t>& pps) {
     187             :   rtc::Optional<SpsParser::SpsState> parsed_sps =
     188           0 :       SpsParser::ParseSps(sps.data(), sps.size());
     189             :   rtc::Optional<PpsParser::PpsState> parsed_pps =
     190           0 :       PpsParser::ParsePps(pps.data(), pps.size());
     191             : 
     192           0 :   if (!parsed_pps || !parsed_sps) {
     193           0 :     LOG(LS_WARNING) << "Failed to parse SPS or PPS parameters.";
     194           0 :     return;
     195             :   }
     196             : 
     197           0 :   SpsInfo sps_info;
     198           0 :   sps_info.size = sps.size();
     199           0 :   uint8_t* sps_data = new uint8_t[sps_info.size];
     200           0 :   memcpy(sps_data, sps.data(), sps_info.size);
     201           0 :   sps_info.data.reset(sps_data);
     202           0 :   sps_data_[parsed_sps->id] = std::move(sps_info);
     203             : 
     204           0 :   PpsInfo pps_info;
     205           0 :   pps_info.size = pps.size();
     206           0 :   pps_info.sps_id = parsed_pps->sps_id;
     207           0 :   uint8_t* pps_data = new uint8_t[pps_info.size];
     208           0 :   memcpy(pps_data, pps.data(), pps_info.size);
     209           0 :   pps_info.data.reset(pps_data);
     210           0 :   pps_data_[parsed_pps->id] = std::move(pps_info);
     211             : }
     212             : 
     213             : }  // namespace video_coding
     214             : }  // namespace webrtc

Generated by: LCOV version 1.13