Add iOS SDK unit tests for nalu_rewriter
Bug: webrtc:9939
Change-Id: I6848786009ee10ffed60743d9e3a2acaf65540c6
Reviewed-on: https://webrtc-review.googlesource.com/c/108440
Reviewed-by: Artem Titarenko <artit@webrtc.org>
Reviewed-by: Peter Hanspers <peterhanspers@webrtc.org>
Commit-Queue: Peter Hanspers <peterhanspers@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25422}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index a8a1b03..ff731ba 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -1037,6 +1037,7 @@
"objc/unittests/RTCPeerConnectionFactory_xctest.m",
"objc/unittests/frame_buffer_helpers.h",
"objc/unittests/frame_buffer_helpers.mm",
+ "objc/unittests/nalu_rewriter_xctest.mm",
]
# TODO(peterhanspers): Reenable these tests on simulator.
@@ -1059,6 +1060,7 @@
":native_api_audio_device_module",
":native_video",
":peerconnectionfactory_base_objc",
+ ":video_toolbox_cc",
":videocapture_objc",
":videocodec_objc",
":videoframebuffer_objc",
@@ -1599,7 +1601,10 @@
}
rtc_static_library("video_toolbox_cc") {
- visibility = [ ":videotoolbox_objc" ]
+ visibility = [
+ ":videotoolbox_objc",
+ ":sdk_unittests_sources",
+ ]
sources = [
"objc/components/video_codec/helpers.cc",
"objc/components/video_codec/helpers.h",
diff --git a/sdk/objc/components/video_codec/nalu_rewriter_unittest.cc b/sdk/objc/components/video_codec/nalu_rewriter_unittest.cc
deleted file mode 100644
index 4dc00c9..0000000
--- a/sdk/objc/components/video_codec/nalu_rewriter_unittest.cc
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- *
- */
-
-#include <memory>
-
-#include "common_video/h264/h264_common.h"
-#include "rtc_base/arraysize.h"
-#include "sdk/objc/components/video_codec/nalu_rewriter.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-
-using H264::kSps;
-
-static const uint8_t NALU_TEST_DATA_0[] = {0xAA, 0xBB, 0xCC};
-static const uint8_t NALU_TEST_DATA_1[] = {0xDE, 0xAD, 0xBE, 0xEF};
-
-TEST(H264VideoToolboxNaluTest, TestCreateVideoFormatDescription) {
- const uint8_t sps_pps_buffer[] = {
- // SPS nalu.
- 0x00, 0x00, 0x00, 0x01, 0x27, 0x42, 0x00, 0x1E, 0xAB, 0x40, 0xF0, 0x28,
- 0xD3, 0x70, 0x20, 0x20, 0x20, 0x20,
- // PPS nalu.
- 0x00, 0x00, 0x00, 0x01, 0x28, 0xCE, 0x3C, 0x30};
- CMVideoFormatDescriptionRef description =
- CreateVideoFormatDescription(sps_pps_buffer, arraysize(sps_pps_buffer));
- EXPECT_TRUE(description);
- if (description) {
- CFRelease(description);
- description = nullptr;
- }
-
- const uint8_t sps_pps_not_at_start_buffer[] = {
- // Add some non-SPS/PPS NALUs at the beginning
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x01,
- 0xAB, 0x33, 0x21,
- // SPS nalu.
- 0x00, 0x00, 0x01, 0x27, 0x42, 0x00, 0x1E, 0xAB, 0x40, 0xF0, 0x28, 0xD3,
- 0x70, 0x20, 0x20, 0x20, 0x20,
- // PPS nalu.
- 0x00, 0x00, 0x01, 0x28, 0xCE, 0x3C, 0x30};
- description = CreateVideoFormatDescription(
- sps_pps_not_at_start_buffer, arraysize(sps_pps_not_at_start_buffer));
- EXPECT_TRUE(description);
- if (description) {
- CFRelease(description);
- description = nullptr;
- }
-
- const uint8_t other_buffer[] = {0x00, 0x00, 0x00, 0x01, 0x28};
- EXPECT_FALSE(
- CreateVideoFormatDescription(other_buffer, arraysize(other_buffer)));
-}
-
-TEST(AnnexBBufferReaderTest, TestReadEmptyInput) {
- const uint8_t annex_b_test_data[] = {0x00};
- AnnexBBufferReader reader(annex_b_test_data, 0);
- const uint8_t* nalu = nullptr;
- size_t nalu_length = 0;
- EXPECT_EQ(0u, reader.BytesRemaining());
- EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(nullptr, nalu);
- EXPECT_EQ(0u, nalu_length);
-}
-
-TEST(AnnexBBufferReaderTest, TestReadSingleNalu) {
- const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x00, 0x01, 0xAA};
- AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
- const uint8_t* nalu = nullptr;
- size_t nalu_length = 0;
- EXPECT_EQ(arraysize(annex_b_test_data), reader.BytesRemaining());
- EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(annex_b_test_data + 4, nalu);
- EXPECT_EQ(1u, nalu_length);
- EXPECT_EQ(0u, reader.BytesRemaining());
- EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(nullptr, nalu);
- EXPECT_EQ(0u, nalu_length);
-}
-
-TEST(AnnexBBufferReaderTest, TestReadSingleNalu3ByteHeader) {
- const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x01, 0xAA};
- AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
- const uint8_t* nalu = nullptr;
- size_t nalu_length = 0;
- EXPECT_EQ(arraysize(annex_b_test_data), reader.BytesRemaining());
- EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(annex_b_test_data + 3, nalu);
- EXPECT_EQ(1u, nalu_length);
- EXPECT_EQ(0u, reader.BytesRemaining());
- EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(nullptr, nalu);
- EXPECT_EQ(0u, nalu_length);
-}
-
-TEST(AnnexBBufferReaderTest, TestReadMissingNalu) {
- // clang-format off
- const uint8_t annex_b_test_data[] = {0x01,
- 0x00, 0x01,
- 0x00, 0x00, 0x00, 0xFF};
- // clang-format on
- AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
- const uint8_t* nalu = nullptr;
- size_t nalu_length = 0;
- EXPECT_EQ(0u, reader.BytesRemaining());
- EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(nullptr, nalu);
- EXPECT_EQ(0u, nalu_length);
-}
-
-TEST(AnnexBBufferReaderTest, TestReadMultipleNalus) {
- // clang-format off
- const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x00, 0x01, 0xFF,
- 0x01,
- 0x00, 0x01,
- 0x00, 0x00, 0x00, 0xFF,
- 0x00, 0x00, 0x01, 0xAA, 0xBB};
- // clang-format on
- AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
- const uint8_t* nalu = nullptr;
- size_t nalu_length = 0;
- EXPECT_EQ(arraysize(annex_b_test_data), reader.BytesRemaining());
- EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(annex_b_test_data + 4, nalu);
- EXPECT_EQ(8u, nalu_length);
- EXPECT_EQ(6u, reader.BytesRemaining());
- EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(annex_b_test_data + 16, nalu);
- EXPECT_EQ(2u, nalu_length);
- EXPECT_EQ(0u, reader.BytesRemaining());
- EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(nullptr, nalu);
- EXPECT_EQ(0u, nalu_length);
-}
-
-TEST(AnnexBBufferReaderTest, TestFindNextNaluOfType) {
- const uint8_t notSps = 0x1F;
- const uint8_t annex_b_test_data[] = {
- 0x00, 0x00, 0x00, 0x01, kSps, 0x00, 0x00, 0x01, notSps,
- 0x00, 0x00, 0x01, notSps, 0xDD, 0x00, 0x00, 0x01, notSps,
- 0xEE, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x01, kSps, 0xBB, 0x00, 0x00,
- 0x01, notSps, 0x00, 0x00, 0x01, notSps, 0xDD, 0x00, 0x00,
- 0x01, notSps, 0xEE, 0xFF, 0x00, 0x00, 0x00, 0x01};
-
- AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
- const uint8_t* nalu = nullptr;
- size_t nalu_length = 0;
- EXPECT_EQ(arraysize(annex_b_test_data), reader.BytesRemaining());
- EXPECT_TRUE(reader.FindNextNaluOfType(kSps));
- EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(annex_b_test_data + 4, nalu);
- EXPECT_EQ(1u, nalu_length);
-
- EXPECT_TRUE(reader.FindNextNaluOfType(kSps));
- EXPECT_TRUE(reader.ReadNalu(&nalu, &nalu_length));
- EXPECT_EQ(annex_b_test_data + 32, nalu);
- EXPECT_EQ(2u, nalu_length);
-
- EXPECT_FALSE(reader.FindNextNaluOfType(kSps));
- EXPECT_FALSE(reader.ReadNalu(&nalu, &nalu_length));
-}
-
-TEST(AvccBufferWriterTest, TestEmptyOutputBuffer) {
- const uint8_t expected_buffer[] = {0x00};
- const size_t buffer_size = 1;
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
- memset(buffer.get(), 0, buffer_size);
- AvccBufferWriter writer(buffer.get(), 0);
- EXPECT_EQ(0u, writer.BytesRemaining());
- EXPECT_FALSE(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
- EXPECT_EQ(0,
- memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
-}
-
-TEST(AvccBufferWriterTest, TestWriteSingleNalu) {
- const uint8_t expected_buffer[] = {
- 0x00, 0x00, 0x00, 0x03, 0xAA, 0xBB, 0xCC,
- };
- const size_t buffer_size = arraysize(NALU_TEST_DATA_0) + 4;
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
- AvccBufferWriter writer(buffer.get(), buffer_size);
- EXPECT_EQ(buffer_size, writer.BytesRemaining());
- EXPECT_TRUE(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
- EXPECT_EQ(0u, writer.BytesRemaining());
- EXPECT_FALSE(writer.WriteNalu(NALU_TEST_DATA_1, arraysize(NALU_TEST_DATA_1)));
- EXPECT_EQ(0,
- memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
-}
-
-TEST(AvccBufferWriterTest, TestWriteMultipleNalus) {
- // clang-format off
- const uint8_t expected_buffer[] = {
- 0x00, 0x00, 0x00, 0x03, 0xAA, 0xBB, 0xCC,
- 0x00, 0x00, 0x00, 0x04, 0xDE, 0xAD, 0xBE, 0xEF
- };
- // clang-format on
- const size_t buffer_size =
- arraysize(NALU_TEST_DATA_0) + arraysize(NALU_TEST_DATA_1) + 8;
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
- AvccBufferWriter writer(buffer.get(), buffer_size);
- EXPECT_EQ(buffer_size, writer.BytesRemaining());
- EXPECT_TRUE(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
- EXPECT_EQ(buffer_size - (arraysize(NALU_TEST_DATA_0) + 4),
- writer.BytesRemaining());
- EXPECT_TRUE(writer.WriteNalu(NALU_TEST_DATA_1, arraysize(NALU_TEST_DATA_1)));
- EXPECT_EQ(0u, writer.BytesRemaining());
- EXPECT_EQ(0,
- memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
-}
-
-TEST(AvccBufferWriterTest, TestOverflow) {
- const uint8_t expected_buffer[] = {0x00, 0x00, 0x00};
- const size_t buffer_size = arraysize(NALU_TEST_DATA_0);
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
- memset(buffer.get(), 0, buffer_size);
- AvccBufferWriter writer(buffer.get(), buffer_size);
- EXPECT_EQ(buffer_size, writer.BytesRemaining());
- EXPECT_FALSE(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
- EXPECT_EQ(buffer_size, writer.BytesRemaining());
- EXPECT_EQ(0,
- memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
-}
-
-} // namespace webrtc
diff --git a/sdk/objc/unittests/nalu_rewriter_xctest.mm b/sdk/objc/unittests/nalu_rewriter_xctest.mm
new file mode 100644
index 0000000..4b04990
--- /dev/null
+++ b/sdk/objc/unittests/nalu_rewriter_xctest.mm
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "common_video/h264/h264_common.h"
+#include "components/video_codec/nalu_rewriter.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/gunit.h"
+
+#import <XCTest/XCTest.h>
+
+#if TARGET_OS_IPHONE
+#import <AVFoundation/AVFoundation.h>
+#import <UIKit/UIKit.h>
+#endif
+
+@interface NaluRewriterTests : XCTestCase
+
+@end
+
+static const uint8_t NALU_TEST_DATA_0[] = {0xAA, 0xBB, 0xCC};
+static const uint8_t NALU_TEST_DATA_1[] = {0xDE, 0xAD, 0xBE, 0xEF};
+
+// clang-format off
+static const uint8_t SPS_PPS_BUFFER[] = {
+ // SPS nalu.
+ 0x00, 0x00, 0x00, 0x01, 0x27, 0x42, 0x00, 0x1E, 0xAB, 0x40, 0xF0, 0x28,
+ 0xD3, 0x70, 0x20, 0x20, 0x20, 0x20,
+ // PPS nalu.
+ 0x00, 0x00, 0x00, 0x01, 0x28, 0xCE, 0x3C, 0x30};
+// clang-format on
+
+@implementation NaluRewriterTests
+
+- (void)testCreateVideoFormatDescription {
+ CMVideoFormatDescriptionRef description =
+ webrtc::CreateVideoFormatDescription(SPS_PPS_BUFFER, arraysize(SPS_PPS_BUFFER));
+ XCTAssertTrue(description);
+ if (description) {
+ CFRelease(description);
+ description = nullptr;
+ }
+
+ // clang-format off
+ const uint8_t sps_pps_not_at_start_buffer[] = {
+ // Add some non-SPS/PPS NALUs at the beginning
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x01,
+ 0xAB, 0x33, 0x21,
+ // SPS nalu.
+ 0x00, 0x00, 0x01, 0x27, 0x42, 0x00, 0x1E, 0xAB, 0x40, 0xF0, 0x28, 0xD3,
+ 0x70, 0x20, 0x20, 0x20, 0x20,
+ // PPS nalu.
+ 0x00, 0x00, 0x01, 0x28, 0xCE, 0x3C, 0x30};
+ // clang-format on
+ description = webrtc::CreateVideoFormatDescription(sps_pps_not_at_start_buffer,
+ arraysize(sps_pps_not_at_start_buffer));
+
+ XCTAssertTrue(description);
+
+ if (description) {
+ CFRelease(description);
+ description = nullptr;
+ }
+
+ const uint8_t other_buffer[] = {0x00, 0x00, 0x00, 0x01, 0x28};
+ XCTAssertFalse(webrtc::CreateVideoFormatDescription(other_buffer, arraysize(other_buffer)));
+}
+
+- (void)testReadEmptyInput {
+ const uint8_t annex_b_test_data[] = {0x00};
+ webrtc::AnnexBBufferReader reader(annex_b_test_data, 0);
+ const uint8_t* nalu = nullptr;
+ size_t nalu_length = 0;
+ XCTAssertEqual(0u, reader.BytesRemaining());
+ XCTAssertFalse(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(nullptr, nalu);
+ XCTAssertEqual(0u, nalu_length);
+}
+
+- (void)testReadSingleNalu {
+ const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x00, 0x01, 0xAA};
+ webrtc::AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
+ const uint8_t* nalu = nullptr;
+ size_t nalu_length = 0;
+ XCTAssertEqual(arraysize(annex_b_test_data), reader.BytesRemaining());
+ XCTAssertTrue(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(annex_b_test_data + 4, nalu);
+ XCTAssertEqual(1u, nalu_length);
+ XCTAssertEqual(0u, reader.BytesRemaining());
+ XCTAssertFalse(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(nullptr, nalu);
+ XCTAssertEqual(0u, nalu_length);
+}
+
+- (void)testReadSingleNalu3ByteHeader {
+ const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x01, 0xAA};
+ webrtc::AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
+ const uint8_t* nalu = nullptr;
+ size_t nalu_length = 0;
+ XCTAssertEqual(arraysize(annex_b_test_data), reader.BytesRemaining());
+ XCTAssertTrue(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(annex_b_test_data + 3, nalu);
+ XCTAssertEqual(1u, nalu_length);
+ XCTAssertEqual(0u, reader.BytesRemaining());
+ XCTAssertFalse(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(nullptr, nalu);
+ XCTAssertEqual(0u, nalu_length);
+}
+
+- (void)testReadMissingNalu {
+ // clang-format off
+ const uint8_t annex_b_test_data[] = {0x01,
+ 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0xFF};
+ // clang-format on
+ webrtc::AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
+ const uint8_t* nalu = nullptr;
+ size_t nalu_length = 0;
+ XCTAssertEqual(0u, reader.BytesRemaining());
+ XCTAssertFalse(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(nullptr, nalu);
+ XCTAssertEqual(0u, nalu_length);
+}
+
+- (void)testReadMultipleNalus {
+ // clang-format off
+ const uint8_t annex_b_test_data[] = {0x00, 0x00, 0x00, 0x01, 0xFF,
+ 0x01,
+ 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x01, 0xAA, 0xBB};
+ // clang-format on
+ webrtc::AnnexBBufferReader reader(annex_b_test_data, arraysize(annex_b_test_data));
+ const uint8_t* nalu = nullptr;
+ size_t nalu_length = 0;
+ XCTAssertEqual(arraysize(annex_b_test_data), reader.BytesRemaining());
+ XCTAssertTrue(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(annex_b_test_data + 4, nalu);
+ XCTAssertEqual(8u, nalu_length);
+ XCTAssertEqual(5u, reader.BytesRemaining());
+ XCTAssertTrue(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(annex_b_test_data + 15, nalu);
+ XCTAssertEqual(2u, nalu_length);
+ XCTAssertEqual(0u, reader.BytesRemaining());
+ XCTAssertFalse(reader.ReadNalu(&nalu, &nalu_length));
+ XCTAssertEqual(nullptr, nalu);
+ XCTAssertEqual(0u, nalu_length);
+}
+
+- (void)testEmptyOutputBuffer {
+ const uint8_t expected_buffer[] = {0x00};
+ const size_t buffer_size = 1;
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
+ memset(buffer.get(), 0, buffer_size);
+ webrtc::AvccBufferWriter writer(buffer.get(), 0);
+ XCTAssertEqual(0u, writer.BytesRemaining());
+ XCTAssertFalse(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
+ XCTAssertEqual(0, memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
+}
+
+- (void)testWriteSingleNalu {
+ const uint8_t expected_buffer[] = {
+ 0x00, 0x00, 0x00, 0x03, 0xAA, 0xBB, 0xCC,
+ };
+ const size_t buffer_size = arraysize(NALU_TEST_DATA_0) + 4;
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
+ webrtc::AvccBufferWriter writer(buffer.get(), buffer_size);
+ XCTAssertEqual(buffer_size, writer.BytesRemaining());
+ XCTAssertTrue(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
+ XCTAssertEqual(0u, writer.BytesRemaining());
+ XCTAssertFalse(writer.WriteNalu(NALU_TEST_DATA_1, arraysize(NALU_TEST_DATA_1)));
+ XCTAssertEqual(0, memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
+}
+
+- (void)testWriteMultipleNalus {
+ // clang-format off
+ const uint8_t expected_buffer[] = {
+ 0x00, 0x00, 0x00, 0x03, 0xAA, 0xBB, 0xCC,
+ 0x00, 0x00, 0x00, 0x04, 0xDE, 0xAD, 0xBE, 0xEF
+ };
+ // clang-format on
+ const size_t buffer_size = arraysize(NALU_TEST_DATA_0) + arraysize(NALU_TEST_DATA_1) + 8;
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
+ webrtc::AvccBufferWriter writer(buffer.get(), buffer_size);
+ XCTAssertEqual(buffer_size, writer.BytesRemaining());
+ XCTAssertTrue(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
+ XCTAssertEqual(buffer_size - (arraysize(NALU_TEST_DATA_0) + 4), writer.BytesRemaining());
+ XCTAssertTrue(writer.WriteNalu(NALU_TEST_DATA_1, arraysize(NALU_TEST_DATA_1)));
+ XCTAssertEqual(0u, writer.BytesRemaining());
+ XCTAssertEqual(0, memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
+}
+
+- (void)testOverflow {
+ const uint8_t expected_buffer[] = {0x00, 0x00, 0x00};
+ const size_t buffer_size = arraysize(NALU_TEST_DATA_0);
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
+ memset(buffer.get(), 0, buffer_size);
+ webrtc::AvccBufferWriter writer(buffer.get(), buffer_size);
+ XCTAssertEqual(buffer_size, writer.BytesRemaining());
+ XCTAssertFalse(writer.WriteNalu(NALU_TEST_DATA_0, arraysize(NALU_TEST_DATA_0)));
+ XCTAssertEqual(buffer_size, writer.BytesRemaining());
+ XCTAssertEqual(0, memcmp(expected_buffer, buffer.get(), arraysize(expected_buffer)));
+}
+
+- (void)testH264AnnexBBufferToCMSampleBuffer {
+ // clang-format off
+ const uint8_t annex_b_test_data[] = {
+ 0x00,
+ 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0xFF, // first chunk, 4 bytes
+ 0x00, 0x00, 0x01,
+ 0xAA, 0xFF, // second chunk, 2 bytes
+ 0x00, 0x00, 0x01,
+ 0xBB}; // third chunk, 1 byte, will not fit into output array
+
+ const uint8_t expected_cmsample_data[] = {
+ 0x00, 0x00, 0x00, 0x04,
+ 0x01, 0x00, 0x00, 0xFF, // first chunk, 4 bytes
+ 0x00, 0x00, 0x00, 0x02,
+ 0xAA, 0xFF}; // second chunk, 2 bytes
+ // clang-format on
+
+ CMMemoryPoolRef memory_pool = CMMemoryPoolCreate(nil);
+ CMSampleBufferRef out_sample_buffer = nil;
+ CMVideoFormatDescriptionRef description = [self createDescription];
+
+ Boolean result = webrtc::H264AnnexBBufferToCMSampleBuffer(annex_b_test_data,
+ arraysize(annex_b_test_data),
+ description,
+ &out_sample_buffer,
+ memory_pool);
+
+ XCTAssertTrue(result);
+
+ XCTAssertEqual(description, CMSampleBufferGetFormatDescription(out_sample_buffer));
+
+ char* data_ptr = nullptr;
+ CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(out_sample_buffer);
+ size_t block_buffer_size = CMBlockBufferGetDataLength(block_buffer);
+ CMBlockBufferGetDataPointer(block_buffer, 0, nullptr, nullptr, &data_ptr);
+ XCTAssertEqual(block_buffer_size, arraysize(annex_b_test_data));
+
+ int data_comparison_result =
+ memcmp(expected_cmsample_data, data_ptr, arraysize(expected_cmsample_data));
+
+ XCTAssertEqual(0, data_comparison_result);
+
+ if (description) {
+ CFRelease(description);
+ description = nullptr;
+ }
+
+ CMMemoryPoolInvalidate(memory_pool);
+ CFRelease(memory_pool);
+}
+
+- (void)testH264CMSampleBufferToAnnexBBuffer {
+ // clang-format off
+ const uint8_t cmsample_data[] = {
+ 0x00, 0x00, 0x00, 0x04,
+ 0x01, 0x00, 0x00, 0xFF, // first chunk, 4 bytes
+ 0x00, 0x00, 0x00, 0x02,
+ 0xAA, 0xFF}; // second chunk, 2 bytes
+
+ const uint8_t expected_annex_b_data[] = {
+ 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0xFF, // first chunk, 4 bytes
+ 0x00, 0x00, 0x00, 0x01,
+ 0xAA, 0xFF}; // second chunk, 2 bytes
+ // clang-format on
+
+ rtc::Buffer annexb_buffer(arraysize(cmsample_data));
+ std::unique_ptr<webrtc::RTPFragmentationHeader> out_header_ptr;
+ CMSampleBufferRef sample_buffer =
+ [self createCMSampleBufferRef:(void*)cmsample_data cmsampleSize:arraysize(cmsample_data)];
+
+ Boolean result = webrtc::H264CMSampleBufferToAnnexBBuffer(sample_buffer,
+ /* is_keyframe */ false,
+ &annexb_buffer,
+ &out_header_ptr);
+
+ XCTAssertTrue(result);
+
+ XCTAssertEqual(arraysize(expected_annex_b_data), annexb_buffer.size());
+
+ int data_comparison_result =
+ memcmp(expected_annex_b_data, annexb_buffer.data(), arraysize(expected_annex_b_data));
+
+ XCTAssertEqual(0, data_comparison_result);
+
+ webrtc::RTPFragmentationHeader* out_header = out_header_ptr.get();
+
+ XCTAssertEqual(2, (int)out_header->Size());
+
+ XCTAssertEqual(4, (int)out_header->Offset(0));
+ XCTAssertEqual(4, (int)out_header->Length(0));
+ XCTAssertEqual(0, (int)out_header->TimeDiff(0));
+ XCTAssertEqual(0, (int)out_header->PayloadType(0));
+
+ XCTAssertEqual(12, (int)out_header->Offset(1));
+ XCTAssertEqual(2, (int)out_header->Length(1));
+ XCTAssertEqual(0, (int)out_header->TimeDiff(1));
+ XCTAssertEqual(0, (int)out_header->PayloadType(1));
+}
+
+- (void)testH264CMSampleBufferToAnnexBBufferWithKeyframe {
+ // clang-format off
+ const uint8_t cmsample_data[] = {
+ 0x00, 0x00, 0x00, 0x04,
+ 0x01, 0x00, 0x00, 0xFF, // first chunk, 4 bytes
+ 0x00, 0x00, 0x00, 0x02,
+ 0xAA, 0xFF}; // second chunk, 2 bytes
+
+ const uint8_t expected_annex_b_data[] = {
+ 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0xFF, // first chunk, 4 bytes
+ 0x00, 0x00, 0x00, 0x01,
+ 0xAA, 0xFF}; // second chunk, 2 bytes
+ // clang-format on
+
+ rtc::Buffer annexb_buffer(arraysize(cmsample_data));
+ std::unique_ptr<webrtc::RTPFragmentationHeader> out_header_ptr;
+ CMSampleBufferRef sample_buffer =
+ [self createCMSampleBufferRef:(void*)cmsample_data cmsampleSize:arraysize(cmsample_data)];
+
+ Boolean result = webrtc::H264CMSampleBufferToAnnexBBuffer(sample_buffer,
+ /* is_keyframe */ true,
+ &annexb_buffer,
+ &out_header_ptr);
+
+ XCTAssertTrue(result);
+
+ XCTAssertEqual(arraysize(SPS_PPS_BUFFER) + arraysize(expected_annex_b_data),
+ annexb_buffer.size());
+
+ XCTAssertEqual(0, memcmp(SPS_PPS_BUFFER, annexb_buffer.data(), arraysize(SPS_PPS_BUFFER)));
+
+ XCTAssertEqual(0,
+ memcmp(expected_annex_b_data,
+ annexb_buffer.data() + arraysize(SPS_PPS_BUFFER),
+ arraysize(expected_annex_b_data)));
+
+ webrtc::RTPFragmentationHeader* out_header = out_header_ptr.get();
+
+ XCTAssertEqual(4, (int)out_header->Size());
+
+ XCTAssertEqual(4, (int)out_header->Offset(0));
+ XCTAssertEqual(14, (int)out_header->Length(0));
+ XCTAssertEqual(0, (int)out_header->TimeDiff(0));
+ XCTAssertEqual(0, (int)out_header->PayloadType(0));
+
+ XCTAssertEqual(22, (int)out_header->Offset(1));
+ XCTAssertEqual(4, (int)out_header->Length(1));
+ XCTAssertEqual(0, (int)out_header->TimeDiff(1));
+ XCTAssertEqual(0, (int)out_header->PayloadType(1));
+
+ XCTAssertEqual(30, (int)out_header->Offset(2));
+ XCTAssertEqual(4, (int)out_header->Length(2));
+ XCTAssertEqual(0, (int)out_header->TimeDiff(2));
+ XCTAssertEqual(0, (int)out_header->PayloadType(2));
+
+ XCTAssertEqual(38, (int)out_header->Offset(3));
+ XCTAssertEqual(2, (int)out_header->Length(3));
+ XCTAssertEqual(0, (int)out_header->TimeDiff(3));
+ XCTAssertEqual(0, (int)out_header->PayloadType(3));
+}
+
+- (CMVideoFormatDescriptionRef)createDescription {
+ CMVideoFormatDescriptionRef description =
+ webrtc::CreateVideoFormatDescription(SPS_PPS_BUFFER, arraysize(SPS_PPS_BUFFER));
+ XCTAssertTrue(description);
+ return description;
+}
+
+- (CMSampleBufferRef)createCMSampleBufferRef:(void*)cmsampleData cmsampleSize:(size_t)cmsampleSize {
+ CMSampleBufferRef sample_buffer = nil;
+ OSStatus status;
+
+ CMVideoFormatDescriptionRef description = [self createDescription];
+ CMBlockBufferRef block_buffer = nullptr;
+
+ status = CMBlockBufferCreateWithMemoryBlock(nullptr,
+ cmsampleData,
+ cmsampleSize,
+ nullptr,
+ nullptr,
+ 0,
+ cmsampleSize,
+ kCMBlockBufferAssureMemoryNowFlag,
+ &block_buffer);
+
+ status = CMSampleBufferCreate(nullptr,
+ block_buffer,
+ true,
+ nullptr,
+ nullptr,
+ description,
+ 1,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ &sample_buffer);
+
+ return sample_buffer;
+}
+
+@end