[Matroska-devel] MVC codec in Matroska container

Peter Wimmer (Lists) peter.wimmer.lists at 3dtv.at
Tue Dec 11 16:51:26 CET 2012


Hi,



I've added Mike's MVC proposal to the MPC-HC Matroska Source and tested it with his sample file. It works as expected. Attached is the patch and below is the new code for MatroskaSplitter.cpp that parses CodecPrivate. As you can see, parsing the mvcC atom is pretty simple.






} else if (CodecID.Find("V_MPEG4/ISO/AVC") == 0) {
  unsigned jj = 0;
  std::vector<BYTE> avcC;
  for (size_t i = 0; i < pTE->CodecPrivate.GetCount(); i++) {
      avcC.push_back(pTE->CodecPrivate[i]);
  }

  for (unsigned index = 0; jj + 6 <= pTE->CodecPrivate.GetCount(); index++) {
      // CodecPrivate always starts with an avcC atom without
      // length and ID and might be followed by other atoms
      // that include length and ID. We currently support the
      // mvcC atom only.
      DWORD id = 'avcC';
      if (index > 0) {
        unsigned len = avcC[jj] << 24 | avcC[jj+1] << 16 | avcC[jj+2] << 8 | avcC[jj+3];
        id = avcC[jj+4] << 24 | avcC[jj+5] << 16 | avcC[jj+6] << 8 | avcC[jj+7];
        if (id == 'mvcC') {
          jj += 8;
        } else {
          jj += 4 + len;
          continue;
        }
      }

      bool error = false;
      std::vector<BYTE> sh;

      DWORD profile = avcC[jj+1];
      DWORD level = avcC[jj+3];
      DWORD flags = (avcC[jj+4] & 3) + 1;

      jj += 5;
      BYTE sps = avcC[jj++] & 0x1f;

      while (!error && sps--) {
          if (jj + 2 > avcC.size()) {
              error = true;
              break;
          }
          unsigned spslen = ((unsigned)avcC[jj] << 8) | avcC[jj + 1];
          if (jj + 2 + spslen > avcC.size()) {
              error = true;
              break;
          }
          unsigned cur = sh.size();
          sh.resize(cur + spslen + 2, 0);
          std::copy(avcC.begin() + jj, avcC.begin() + jj + 2 + spslen, sh.begin() + cur);
          jj += 2 + spslen;
      }

      if (error || jj + 1 > avcC.size()) {
          break;
      }

      unsigned pps = avcC[jj++];

      while (!error && pps--) {
          if (jj + 2 > avcC.size()) {
              error = true;
              break;
          }
          unsigned ppslen = ((unsigned)avcC[jj] << 8) | avcC[jj + 1];
          if (jj + 2 + ppslen > avcC.size()) {
              error = true;
              break;
          }
          unsigned cur = sh.size();
          sh.resize(cur + ppslen + 2, 0);
          std::copy(avcC.begin() + jj, avcC.begin() + jj + 2 + ppslen, sh.begin() + cur);
          jj += 2 + ppslen;
      }

      if (error) {
        break;
      }

      CAtlArray<BYTE> data;
      data.SetCount(sh.size());
      std::copy(sh.begin(), sh.end(), data.GetData());

      if (id == 'mvcC') {
          mt.subtype = FOURCCMap('CVMA');
      } else {
          mt.subtype = FOURCCMap('1CVA');
      }
      mt.formattype = FORMAT_MPEG2Video;
      MPEG2VIDEOINFO* pm2vi = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + data.GetCount());
      memset(mt.Format(), 0, mt.FormatLength());
      pm2vi->hdr.bmiHeader.biSize = sizeof(pm2vi->hdr.bmiHeader);
      pm2vi->hdr.bmiHeader.biWidth = (LONG)pTE->v.PixelWidth;
      pm2vi->hdr.bmiHeader.biHeight = (LONG)pTE->v.PixelHeight;
      if (id == 'mvcC') {
          pm2vi->hdr.bmiHeader.biCompression = 'CVMA';
      } else {
          pm2vi->hdr.bmiHeader.biCompression = '1CVA';
      }
      pm2vi->hdr.bmiHeader.biPlanes = 1;
      pm2vi->hdr.bmiHeader.biBitCount = 24;
      pm2vi->dwProfile = profile;
      pm2vi->dwLevel = level;
      pm2vi->dwFlags = flags;
      BYTE* pSequenceHeader = (BYTE*)pm2vi->dwSequenceHeader;
      memcpy(pSequenceHeader, data.GetData(), data.GetCount());
      pm2vi->cbSequenceHeader = (DWORD)data.GetCount();

      // The MVC media type is only added if an AVC type is
      // already present. The MVC type is added at the first
      // position so that MVC decoders are preferred over AVC
      // decoders during graph building.
      if (id == 'mvcC') {
          if (bHasVideo) {
              mts.InsertAt(0, mt);
          }
      } else {
          if (!bHasVideo) {
              mts.Add(mt);
          }
          bHasVideo = true;
      }
  }


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.matroska.org/pipermail/matroska-devel/attachments/20121211/a1a48ff9/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MPC-HC Matroska Splitter MVC support.patch
Type: application/octet-stream
Size: 9856 bytes
Desc: MPC-HC Matroska Splitter MVC support.patch
URL: <http://lists.matroska.org/pipermail/matroska-devel/attachments/20121211/a1a48ff9/attachment-0001.obj>


More information about the Matroska-devel mailing list