diff --git a/sdk/android/src/jni/video_encoder_wrapper.cc b/sdk/android/src/jni/video_encoder_wrapper.cc index c12f5cff52..1b34e99dce 100644 --- a/sdk/android/src/jni/video_encoder_wrapper.cc +++ b/sdk/android/src/jni/video_encoder_wrapper.cc @@ -254,12 +254,13 @@ void VideoEncoderWrapper::OnEncodedFrame( frame_copy.SetTimestamp(frame_extra_info.timestamp_rtp); frame_copy.capture_time_ms_ = capture_time_ns / rtc::kNumNanosecsPerMillisec; + RTPFragmentationHeader header = ParseFragmentationHeader(frame); if (frame_copy.qp_ < 0) frame_copy.qp_ = ParseQp(frame); CodecSpecificInfo info(ParseCodecSpecificInfo(frame)); - callback_->OnEncodedImage(frame_copy, &info); + callback_->OnEncodedImage(frame_copy, &info, &header); } int32_t VideoEncoderWrapper::HandleReturnCode(JNIEnv* jni, @@ -288,6 +289,35 @@ int32_t VideoEncoderWrapper::HandleReturnCode(JNIEnv* jni, return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; } +RTPFragmentationHeader VideoEncoderWrapper::ParseFragmentationHeader( + rtc::ArrayView buffer) { + RTPFragmentationHeader header; + if (codec_settings_.codecType == kVideoCodecH264) { + h264_bitstream_parser_.ParseBitstream(buffer.data(), buffer.size()); + + // For H.264 search for start codes. + const std::vector nalu_idxs = + H264::FindNaluIndices(buffer.data(), buffer.size()); + if (nalu_idxs.empty()) { + RTC_LOG(LS_ERROR) << "Start code is not found!"; + RTC_LOG(LS_ERROR) << "Data:" << buffer[0] << " " << buffer[1] << " " + << buffer[2] << " " << buffer[3] << " " << buffer[4] + << " " << buffer[5]; + } + header.VerifyAndAllocateFragmentationHeader(nalu_idxs.size()); + for (size_t i = 0; i < nalu_idxs.size(); i++) { + header.fragmentationOffset[i] = nalu_idxs[i].payload_start_offset; + header.fragmentationLength[i] = nalu_idxs[i].payload_size; + } + } else { + // Generate a header describing a single fragment. + header.VerifyAndAllocateFragmentationHeader(1); + header.fragmentationOffset[0] = 0; + header.fragmentationLength[0] = buffer.size(); + } + return header; +} + int VideoEncoderWrapper::ParseQp(rtc::ArrayView buffer) { int qp; bool success; @@ -299,7 +329,6 @@ int VideoEncoderWrapper::ParseQp(rtc::ArrayView buffer) { success = vp9::GetQp(buffer.data(), buffer.size(), &qp); break; case kVideoCodecH264: - h264_bitstream_parser_.ParseBitstream(buffer.data(), buffer.size()); success = h264_bitstream_parser_.GetLastSliceQp(&qp); break; default: // Default is to not provide QP. diff --git a/sdk/android/src/jni/video_encoder_wrapper.h b/sdk/android/src/jni/video_encoder_wrapper.h index cee3a609a3..0e9d37bf23 100644 --- a/sdk/android/src/jni/video_encoder_wrapper.h +++ b/sdk/android/src/jni/video_encoder_wrapper.h @@ -67,6 +67,8 @@ class VideoEncoderWrapper : public VideoEncoder { const JavaRef& j_value, const char* method_name); + RTPFragmentationHeader ParseFragmentationHeader( + rtc::ArrayView buffer); int ParseQp(rtc::ArrayView buffer); CodecSpecificInfo ParseCodecSpecificInfo(const EncodedImage& frame); ScopedJavaLocalRef ToJavaBitrateAllocation(