Skip to content

Commit c5269d8

Browse files
youennfphiln
authored andcommitted
[Cocoa] WebCodecs H265 decoder should reorder frames according presentation time
https://bugs.webkit.org/show_bug.cgi?id=265389 rdar://problem/118836800 Reviewed by Eric Carlson. We compute the reorder queue size by parsing SPS. We reuse the same queue as RTCVideoDecoderH264 and, for that purpose, refactor the code in a RTCVideoFrameWithOrder class. * LayoutTests/http/tests/webcodecs/hevc-reordering-expected.txt: Added. * LayoutTests/http/tests/webcodecs/hevc-reordering.html: Added. * LayoutTests/platform/glib/TestExpectations: * Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc: * Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.h: * Source/ThirdParty/libwebrtc/Source/webrtc/sdk/WebKit/WebKitDecoder.mm: (-[WK_RTCLocalVideoH264H265VP9Decoder setFormat:size:width:height:]): * Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/RTCVideoDecoderH264.mm: (RTCFrameDecodeParams::RTCFrameDecodeParams): (decompressionOutputCallback): (-[RTCVideoDecoderH264 init]): (-[RTCVideoDecoderH264 decodeData:size:timeStamp:]): (-[RTCVideoDecoderH264 setAVCFormat:size:width:height:]): (-[RTCVideoDecoderH264 flush]): (-[RTCVideoDecoderH264 processFrame:reorderSize:]): (RTCVideoFrameWithOrder::RTCVideoFrameWithOrder): Deleted. (RTCVideoFrameWithOrder::~RTCVideoFrameWithOrder): Deleted. (RTCVideoFrameWithOrder::take): Deleted. * Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/RTCVideoDecoderH265.h: * Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/RTCVideoDecoderH265.mm: (RTCH265FrameDecodeParams::RTCH265FrameDecodeParams): (spsDataFromHvcc): (ComputeH265ReorderSizeFromSPS): (ComputeH265ReorderSizeFromHVCC): (ComputeH265ReorderSizeFromAnnexB): (h265DecompressionOutputCallback): (-[RTCVideoDecoderH265 decodeData:size:timeStamp:]): (-[RTCVideoDecoderH265 setHVCCFormat:size:width:height:]): (-[RTCVideoDecoderH265 resetDecompressionSession]): (-[RTCVideoDecoderH265 flush]): (-[RTCVideoDecoderH265 processFrame:reorderSize:]): (-[RTCVideoDecoderH265 setAVCFormat:size:width:height:]): Deleted. * Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/RTCVideoFrameReorderQueue.h: Added. (webrtc::RTCVideoFrameReorderQueue::RTCVideoFrameWithOrder::RTCVideoFrameWithOrder): (webrtc::RTCVideoFrameReorderQueue::RTCVideoFrameWithOrder::~RTCVideoFrameWithOrder): (webrtc::RTCVideoFrameReorderQueue::RTCVideoFrameWithOrder::take): * Source/ThirdParty/libwebrtc/Source/webrtc/sdk/objc/components/video_codec/RTCVideoFrameReorderQueue.mm: Added. (webrtc::RTCVideoFrameReorderQueue::isEmpty): (webrtc::RTCVideoFrameReorderQueue::reorderSize const): (webrtc::RTCVideoFrameReorderQueue::setReorderSize): (webrtc::RTCVideoFrameReorderQueue::append): (webrtc::RTCVideoFrameReorderQueue::takeIfAvailable): (webrtc::RTCVideoFrameReorderQueue::takeIfAny): * Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj: Canonical link: https://commits.webkit.org/271242@main
1 parent 6499c03 commit c5269d8

6 files changed

Lines changed: 208 additions & 1 deletion

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
PASS Test HEVC reordering
3+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="../../resources/testharness.js"></script>
5+
<script src="../../resources/testharnessreport.js"></script>
6+
</head>
7+
<body>
8+
<script>
9+
let decoder;
10+
promise_test(async () => {
11+
const response = await fetch("/media-resources/media-source/content/test-bframes-hevc.mp4");
12+
const buffer = await response.arrayBuffer();
13+
const hvcCOffset = [705, 130];
14+
const frames = [
15+
[99, 3973, 46304],
16+
[366, 50277, 4531],
17+
[233, 54808, 1371],
18+
[167, 56179, 379],
19+
[133, 56558, 172],
20+
[199, 56730, 120],
21+
[300, 56850, 313],
22+
[266, 57163, 112],
23+
[333, 57275, 150],
24+
[633, 57425, 6427]
25+
];
26+
27+
let frameTimestamps = [];
28+
decoder = new VideoDecoder({
29+
output(frame) {
30+
frameTimestamps.push(frame.timestamp);
31+
frame.close();
32+
},
33+
error(e) {
34+
console.log(e);
35+
}
36+
});
37+
decoder.configure({
38+
codec: 'hev1.1.6.L120.90',
39+
codedWidth: 852,
40+
codedHeight: 480,
41+
visibleRect: {x: 0, y: 0, width: 852, height: 480},
42+
displayWidth: 852,
43+
displayHeight: 480,
44+
format: 'hevc',
45+
description: new Uint8Array(buffer, hvcCOffset[0], hvcCOffset[1])
46+
});
47+
48+
chunks = frames.map((frame, i) => new EncodedVideoChunk({type: i == 0 ? 'key' : 'delta', timestamp: frame[0], duration: 1, data: new Uint8Array(buffer, frame[1], frame[2])}));
49+
50+
chunks.forEach(chunk => decoder.decode(chunk));
51+
await decoder.flush();
52+
53+
assert_array_equals(frameTimestamps, frames.map(frame => frame[0]).sort((a,b) => a - b), "timestamps are ordered");
54+
}, "Test HEVC reordering");
55+
</script>
56+
</body>
57+
</html>

Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
207207
sps_max_sub_layers_minus1 = reader.ReadBits(3);
208208
sps.sps_max_sub_layers_minus1 = sps_max_sub_layers_minus1;
209209
sps.sps_max_dec_pic_buffering_minus1.resize(sps_max_sub_layers_minus1 + 1, 0);
210+
#if WEBRTC_WEBKIT_BUILD
211+
sps.sps_max_num_reorder_pics.resize(sps_max_sub_layers_minus1 + 1, 0);
212+
#endif
210213
// sps_temporal_id_nesting_flag: u(1)
211214
reader.ConsumeBits(1);
212215
// profile_tier_level(1, sps_max_sub_layers_minus1). We are acutally not
@@ -310,7 +313,9 @@ absl::optional<H265SpsParser::SpsState> H265SpsParser::ParseSpsInternal(
310313
// sps_max_dec_pic_buffering_minus1: ue(v)
311314
sps.sps_max_dec_pic_buffering_minus1[i] = reader.ReadExponentialGolomb();
312315
// sps_max_num_reorder_pics: ue(v)
313-
reader.ReadExponentialGolomb();
316+
#if WEBRTC_WEBKIT_BUILD
317+
sps.sps_max_num_reorder_pics[i] = reader.ReadExponentialGolomb();
318+
#endif
314319
// sps_max_latency_increase_plus1: ue(v)
315320
reader.ReadExponentialGolomb();
316321
}

Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h265/h265_sps_parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class H265SpsParser {
5252
uint32_t pic_height_in_luma_samples = 0;
5353
uint32_t log2_max_pic_order_cnt_lsb_minus4 = 0;
5454
std::vector<uint32_t> sps_max_dec_pic_buffering_minus1;
55+
#if WEBRTC_WEBKIT_BUILD
56+
std::vector<uint32_t> sps_max_num_reorder_pics;
57+
#endif
5558
uint32_t log2_min_luma_coding_block_size_minus3 = 0;
5659
uint32_t log2_diff_max_min_luma_coding_block_size = 0;
5760
uint32_t sample_adaptive_offset_enabled_flag = 0;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (C) 2023 Apple Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23+
* THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
#import "base/RTCVideoFrame.h"
27+
#include <deque>
28+
#include "rtc_base/synchronization/mutex.h"
29+
30+
namespace webrtc {
31+
32+
class RTCVideoFrameReorderQueue {
33+
public:
34+
RTCVideoFrameReorderQueue() = default;
35+
36+
struct RTCVideoFrameWithOrder {
37+
RTCVideoFrameWithOrder(RTCVideoFrame* frame, uint64_t reorderSize)
38+
: frame((__bridge_retained void*)frame)
39+
, timeStamp(frame.timeStamp)
40+
, reorderSize(reorderSize)
41+
{
42+
}
43+
44+
~RTCVideoFrameWithOrder()
45+
{
46+
if (frame)
47+
take();
48+
}
49+
50+
RTCVideoFrame* take()
51+
{
52+
auto* rtcFrame = (__bridge_transfer RTCVideoFrame *)frame;
53+
frame = nullptr;
54+
return rtcFrame;
55+
}
56+
57+
void* frame;
58+
uint64_t timeStamp;
59+
uint64_t reorderSize;
60+
};
61+
62+
bool isEmpty();
63+
uint8_t reorderSize() const;
64+
void setReorderSize(uint8_t);
65+
void append(RTCVideoFrame*, uint8_t);
66+
RTCVideoFrame *takeIfAvailable();
67+
RTCVideoFrame *takeIfAny();
68+
69+
private:
70+
std::deque<std::unique_ptr<RTCVideoFrameWithOrder>> _reorderQueue;
71+
uint8_t _reorderSize { 0 };
72+
mutable webrtc::Mutex _reorderQueueLock;
73+
};
74+
75+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2015 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+
#import "RTCVideoFrameReorderQueue.h"
13+
14+
namespace webrtc {
15+
16+
bool RTCVideoFrameReorderQueue::isEmpty()
17+
{
18+
return _reorderQueue.empty();
19+
}
20+
21+
uint8_t RTCVideoFrameReorderQueue::reorderSize() const
22+
{
23+
webrtc::MutexLock lock(&_reorderQueueLock);
24+
return _reorderSize;
25+
}
26+
27+
void RTCVideoFrameReorderQueue::setReorderSize(uint8_t size)
28+
{
29+
webrtc::MutexLock lock(&_reorderQueueLock);
30+
_reorderSize = size;
31+
}
32+
33+
void RTCVideoFrameReorderQueue::append(RTCVideoFrame* frame, uint8_t reorderSize)
34+
{
35+
webrtc::MutexLock lock(&_reorderQueueLock);
36+
_reorderQueue.push_back(std::make_unique<RTCVideoFrameWithOrder>(frame, reorderSize));
37+
std::sort(_reorderQueue.begin(), _reorderQueue.end(), [](auto& a, auto& b) {
38+
return a->timeStamp < b->timeStamp;
39+
});
40+
}
41+
42+
RTCVideoFrame* RTCVideoFrameReorderQueue::takeIfAvailable()
43+
{
44+
webrtc::MutexLock lock(&_reorderQueueLock);
45+
if (_reorderQueue.size() && _reorderQueue.size() > _reorderQueue.front()->reorderSize) {
46+
auto *frame = _reorderQueue.front()->take();
47+
_reorderQueue.pop_front();
48+
return frame;
49+
}
50+
return nil;
51+
}
52+
53+
RTCVideoFrame* RTCVideoFrameReorderQueue::takeIfAny()
54+
{
55+
webrtc::MutexLock lock(&_reorderQueueLock);
56+
if (_reorderQueue.size()) {
57+
auto *frame = _reorderQueue.front()->take();
58+
_reorderQueue.pop_front();
59+
return frame;
60+
}
61+
return nil;
62+
}
63+
64+
}

0 commit comments

Comments
 (0)