Home | History | Annotate | Download | only in mp4
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <string.h>
      6 
      7 #include "base/basictypes.h"
      8 #include "base/strings/string_util.h"
      9 #include "media/base/decrypt_config.h"
     10 #include "media/base/stream_parser_buffer.h"
     11 #include "media/filters/h264_parser.h"
     12 #include "media/formats/mp4/avc.h"
     13 #include "media/formats/mp4/box_definitions.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace media {
     17 namespace mp4 {
     18 
     19 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 };
     20 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 };
     21 static const uint8 kExpected[] = {
     22   0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03,
     23   0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 };
     24 
     25 static const uint8 kExpectedParamSets[] = {
     26   0x00, 0x00, 0x00, 0x01, 0x67, 0x12,
     27   0x00, 0x00, 0x00, 0x01, 0x67, 0x34,
     28   0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78};
     29 
     30 static H264NALU::Type StringToNALUType(const std::string& name) {
     31   if (name == "P")
     32     return H264NALU::kNonIDRSlice;
     33 
     34   if (name == "I")
     35     return H264NALU::kIDRSlice;
     36 
     37   if (name == "SEI")
     38     return H264NALU::kSEIMessage;
     39 
     40   if (name == "SPS")
     41     return H264NALU::kSPS;
     42 
     43   if (name == "SPSExt")
     44     return H264NALU::kSPSExt;
     45 
     46   if (name == "PPS")
     47     return H264NALU::kPPS;
     48 
     49   if (name == "AUD")
     50     return H264NALU::kAUD;
     51 
     52   if (name == "EOSeq")
     53     return H264NALU::kEOSeq;
     54 
     55   if (name == "EOStr")
     56     return H264NALU::kEOStream;
     57 
     58   if (name == "FILL")
     59     return H264NALU::kFiller;
     60 
     61   if (name == "R14")
     62     return H264NALU::kReserved14;
     63 
     64   CHECK(false) << "Unexpected name: " << name;
     65   return H264NALU::kUnspecified;
     66 }
     67 
     68 static std::string NALUTypeToString(int type) {
     69   switch (type) {
     70     case H264NALU::kNonIDRSlice:
     71       return "P";
     72     case H264NALU::kSliceDataA:
     73       return "SDA";
     74     case H264NALU::kSliceDataB:
     75       return "SDB";
     76     case H264NALU::kSliceDataC:
     77       return "SDC";
     78     case H264NALU::kIDRSlice:
     79       return "I";
     80     case H264NALU::kSEIMessage:
     81       return "SEI";
     82     case H264NALU::kSPS:
     83       return "SPS";
     84     case H264NALU::kSPSExt:
     85       return "SPSExt";
     86     case H264NALU::kPPS:
     87       return "PPS";
     88     case H264NALU::kAUD:
     89       return "AUD";
     90     case H264NALU::kEOSeq:
     91       return "EOSeq";
     92     case H264NALU::kEOStream:
     93       return "EOStr";
     94     case H264NALU::kFiller:
     95       return "FILL";
     96     case H264NALU::kReserved14:
     97       return "R14";
     98 
     99     case H264NALU::kUnspecified:
    100     case H264NALU::kReserved15:
    101     case H264NALU::kReserved16:
    102     case H264NALU::kReserved17:
    103     case H264NALU::kReserved18:
    104     case H264NALU::kCodedSliceAux:
    105     case H264NALU::kCodedSliceExtension:
    106       CHECK(false) << "Unexpected type: " << type;
    107       break;
    108   };
    109 
    110   return "UnsupportedType";
    111 }
    112 
    113 static void WriteStartCodeAndNALUType(std::vector<uint8>* buffer,
    114                                       const std::string& nal_unit_type) {
    115   buffer->push_back(0x00);
    116   buffer->push_back(0x00);
    117   buffer->push_back(0x00);
    118   buffer->push_back(0x01);
    119   buffer->push_back(StringToNALUType(nal_unit_type));
    120 }
    121 
    122 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer,
    123                     std::vector<SubsampleEntry>* subsamples) {
    124   DCHECK(!str.empty());
    125 
    126   std::vector<std::string> tokens;
    127   EXPECT_GT(Tokenize(str, " ", &tokens), 0u);
    128 
    129   buffer->clear();
    130   for (size_t i = 0; i < tokens.size(); ++i) {
    131     SubsampleEntry entry;
    132     size_t start = buffer->size();
    133 
    134     WriteStartCodeAndNALUType(buffer, tokens[i]);
    135 
    136     entry.clear_bytes = buffer->size() - start;
    137 
    138     // Write junk for the payload since the current code doesn't
    139     // actually look at it.
    140     buffer->push_back(0x32);
    141     buffer->push_back(0x12);
    142     buffer->push_back(0x67);
    143 
    144     if (subsamples) {
    145       // Simulate the encrypted bits containing something that looks
    146       // like a SPS NALU.
    147       WriteStartCodeAndNALUType(buffer, "SPS");
    148     }
    149 
    150     entry.cypher_bytes = buffer->size() - start - entry.clear_bytes;
    151 
    152     if (subsamples) {
    153       subsamples->push_back(entry);
    154     }
    155   }
    156 }
    157 
    158 std::string AnnexBToString(const std::vector<uint8>& buffer,
    159                            const std::vector<SubsampleEntry>& subsamples) {
    160   std::stringstream ss;
    161 
    162   H264Parser parser;
    163   parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples);
    164 
    165   H264NALU nalu;
    166   bool first = true;
    167   while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) {
    168     if (!first)
    169       ss << " ";
    170     else
    171       first = false;
    172 
    173     ss << NALUTypeToString(nalu.nal_unit_type);
    174   }
    175   return ss.str();
    176 }
    177 
    178 class AVCConversionTest : public testing::TestWithParam<int> {
    179  protected:
    180   void WriteLength(int length_size, int length, std::vector<uint8>* buf) {
    181     DCHECK_GE(length, 0);
    182     DCHECK_LE(length, 255);
    183 
    184     for (int i = 1; i < length_size; i++)
    185       buf->push_back(0);
    186     buf->push_back(length);
    187   }
    188 
    189   void MakeInputForLength(int length_size, std::vector<uint8>* buf) {
    190     buf->clear();
    191 
    192     WriteLength(length_size, sizeof(kNALU1), buf);
    193     buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1));
    194 
    195     WriteLength(length_size, sizeof(kNALU2), buf);
    196     buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2));
    197   }
    198 
    199 };
    200 
    201 TEST_P(AVCConversionTest, ParseCorrectly) {
    202   std::vector<uint8> buf;
    203   std::vector<SubsampleEntry> subsamples;
    204   MakeInputForLength(GetParam(), &buf);
    205   EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
    206   EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples));
    207   EXPECT_EQ(buf.size(), sizeof(kExpected));
    208   EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected)));
    209   EXPECT_EQ("P SDC", AnnexBToString(buf, subsamples));
    210 }
    211 
    212 // Intentionally write NALU sizes that are larger than the buffer.
    213 TEST_P(AVCConversionTest, NALUSizeTooLarge) {
    214   std::vector<uint8> buf;
    215   WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf);
    216   buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
    217   EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
    218 }
    219 
    220 TEST_P(AVCConversionTest, NALUSizeIsZero) {
    221   std::vector<uint8> buf;
    222   WriteLength(GetParam(), 0, &buf);
    223 
    224   WriteLength(GetParam(), sizeof(kNALU1), &buf);
    225   buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
    226 
    227   WriteLength(GetParam(), 0, &buf);
    228 
    229   WriteLength(GetParam(), sizeof(kNALU2), &buf);
    230   buf.insert(buf.end(), kNALU2, kNALU2 + sizeof(kNALU2));
    231 
    232   EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
    233 }
    234 
    235 TEST_P(AVCConversionTest, ParsePartial) {
    236   std::vector<uint8> buf;
    237   MakeInputForLength(GetParam(), &buf);
    238   buf.pop_back();
    239   EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
    240   // This tests a buffer ending in the middle of a NAL length. For length size
    241   // of one, this can't happen, so we skip that case.
    242   if (GetParam() != 1) {
    243     MakeInputForLength(GetParam(), &buf);
    244     buf.erase(buf.end() - (sizeof(kNALU2) + 1), buf.end());
    245     EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
    246   }
    247 }
    248 
    249 TEST_P(AVCConversionTest, ParseEmpty) {
    250   std::vector<uint8> buf;
    251   EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
    252   EXPECT_EQ(0u, buf.size());
    253 }
    254 
    255 INSTANTIATE_TEST_CASE_P(AVCConversionTestValues,
    256                         AVCConversionTest,
    257                         ::testing::Values(1, 2, 4));
    258 
    259 TEST_F(AVCConversionTest, ConvertConfigToAnnexB) {
    260   AVCDecoderConfigurationRecord avc_config;
    261   avc_config.sps_list.resize(2);
    262   avc_config.sps_list[0].push_back(0x67);
    263   avc_config.sps_list[0].push_back(0x12);
    264   avc_config.sps_list[1].push_back(0x67);
    265   avc_config.sps_list[1].push_back(0x34);
    266   avc_config.pps_list.resize(1);
    267   avc_config.pps_list[0].push_back(0x68);
    268   avc_config.pps_list[0].push_back(0x56);
    269   avc_config.pps_list[0].push_back(0x78);
    270 
    271   std::vector<uint8> buf;
    272   std::vector<SubsampleEntry> subsamples;
    273   EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf, &subsamples));
    274   EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0],
    275                       sizeof(kExpectedParamSets)));
    276   EXPECT_EQ("SPS SPS PPS", AnnexBToString(buf, subsamples));
    277 }
    278 
    279 // Verify that we can round trip string -> Annex B -> string.
    280 TEST_F(AVCConversionTest, StringConversionFunctions) {
    281   std::string str =
    282       "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr";
    283   std::vector<uint8> buf;
    284   std::vector<SubsampleEntry> subsamples;
    285   StringToAnnexB(str, &buf, &subsamples);
    286   EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples));
    287 
    288   EXPECT_EQ(str, AnnexBToString(buf, subsamples));
    289 }
    290 
    291 TEST_F(AVCConversionTest, ValidAnnexBConstructs) {
    292   const char* test_cases[] = {
    293     "I",
    294     "I I I I",
    295     "AUD I",
    296     "AUD SPS PPS I",
    297     "I EOSeq",
    298     "I EOSeq EOStr",
    299     "I EOStr",
    300     "P",
    301     "P P P P",
    302     "AUD SPS PPS P",
    303     "SEI SEI I",
    304     "SEI SEI R14 I",
    305     "SPS SPSExt SPS PPS I P",
    306     "R14 SEI I",
    307   };
    308 
    309   for (size_t i = 0; i < arraysize(test_cases); ++i) {
    310     std::vector<uint8> buf;
    311     std::vector<SubsampleEntry> subsamples;
    312     StringToAnnexB(test_cases[i], &buf, NULL);
    313     EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i]
    314                                                      << "' failed";
    315   }
    316 }
    317 
    318 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) {
    319   static const char* test_cases[] = {
    320     "AUD",  // No VCL present.
    321     "SPS PPS",  // No VCL present.
    322     "SPS PPS AUD I",  // Parameter sets must come after AUD.
    323     "SPSExt SPS P",  // SPS must come before SPSExt.
    324     "SPS PPS SPSExt P",  // SPSExt must follow an SPS.
    325     "EOSeq",  // EOSeq must come after a VCL.
    326     "EOStr",  // EOStr must come after a VCL.
    327     "I EOStr EOSeq",  // EOSeq must come before EOStr.
    328     "I R14",  // Reserved14-18 must come before first VCL.
    329     "I SEI",  // SEI must come before first VCL.
    330     "P SPS P", // SPS after first VCL would indicate a new access unit.
    331   };
    332 
    333   for (size_t i = 0; i < arraysize(test_cases); ++i) {
    334     std::vector<uint8> buf;
    335     std::vector<SubsampleEntry> subsamples;
    336     StringToAnnexB(test_cases[i], &buf, NULL);
    337     EXPECT_FALSE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i]
    338                                                       << "' failed";
    339   }
    340 }
    341 
    342 typedef struct {
    343   const char* input;
    344   const char* expected;
    345 } InsertTestCases;
    346 
    347 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) {
    348   static const InsertTestCases test_cases[] = {
    349     { "I", "SPS SPS PPS I" },
    350     { "AUD I", "AUD SPS SPS PPS I" },
    351 
    352     // Cases where param sets in |avc_config| are placed before
    353     // the existing ones.
    354     { "SPS PPS I", "SPS SPS PPS SPS PPS I" },
    355     { "AUD SPS PPS I", "AUD SPS SPS PPS SPS PPS I" },  // Note: params placed
    356                                                        // after AUD.
    357   };
    358 
    359   AVCDecoderConfigurationRecord avc_config;
    360   avc_config.sps_list.resize(2);
    361   avc_config.sps_list[0].push_back(0x67);
    362   avc_config.sps_list[0].push_back(0x12);
    363   avc_config.sps_list[1].push_back(0x67);
    364   avc_config.sps_list[1].push_back(0x34);
    365   avc_config.pps_list.resize(1);
    366   avc_config.pps_list[0].push_back(0x68);
    367   avc_config.pps_list[0].push_back(0x56);
    368   avc_config.pps_list[0].push_back(0x78);
    369 
    370   for (size_t i = 0; i < arraysize(test_cases); ++i) {
    371     std::vector<uint8> buf;
    372     std::vector<SubsampleEntry> subsamples;
    373 
    374     StringToAnnexB(test_cases[i].input, &buf, &subsamples);
    375 
    376     EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf, &subsamples))
    377         << "'" << test_cases[i].input << "' insert failed.";
    378     EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples))
    379         << "'" << test_cases[i].input << "' created invalid AnnexB.";
    380     EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples))
    381         << "'" << test_cases[i].input << "' generated unexpected output.";
    382   }
    383 }
    384 
    385 }  // namespace mp4
    386 }  // namespace media
    387