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