static int
demux_mkv_read_trackaudio (FILE *s, mkv_track_t *track)
{
  uint64_t len, length, l;
  int il;

  track->a_sfreq = 8000.0;
  track->a_channels = 1;

  len = length = ebml_read_length (s, &il);
  len += il;
  while (length > 0)
    {
      switch (ebml_read_id (s, &il))
        {
        case MATROSKA_ID_AUDIOSAMPLINGFREQ:
          {
            long double num = ebml_read_float (s, &l);
            if (num == EBML_FLOAT_INVALID)
              return 0;
            track->a_sfreq = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Sampling frequency: %f\n",
                    track->a_sfreq);
            break;
          }

        case MATROSKA_ID_AUDIOBITDEPTH:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              return 0;
            track->a_bps = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Bit depth: %u\n",
                    track->a_bps);
            break;
          }

        case MATROSKA_ID_AUDIOCHANNELS:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              return 0;
            track->a_channels = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Channels: %u\n",
                    track->a_channels);
            break;
          }

        default:
            ebml_read_skip (s, &l);
            break;
        }
      length -= l + il;
    }
  return len;
}
Exemple #2
0
void test_read_int_and_uint() {
	char* buffer_ptr = NULL;
	size_t buffer_size = 0, pos = 0;
	FILE* f = open_memstream(&buffer_ptr, &buffer_size);
		ebml_element_uint(f, MKV_TimecodeScale, 0x0102030405060708);
		ebml_element_int(f, MKV_TimecodeScale, -1000000);
		ebml_element_int(f, MKV_TimecodeScale, 1000000);
	fclose(f);
	
	ebml_elem_t e = ebml_read_element(buffer_ptr, buffer_size, &pos);
	check(e.id == MKV_TimecodeScale);
	check_int(e.header_size, 3 + 1);
	
	uint64_t uvalue = ebml_read_uint(e.data_ptr, e.data_size);
	check_int(uvalue, 0x0102030405060708);
	
	e = ebml_read_element(buffer_ptr, buffer_size, &pos);
	check(e.id == MKV_TimecodeScale);
	
	int64_t ivalue = ebml_read_int(e.data_ptr, e.data_size);
	check_int(ivalue, -1000000);
	
	e = ebml_read_element(buffer_ptr, buffer_size, &pos);
	check(e.id == MKV_TimecodeScale);
	
	ivalue = ebml_read_int(e.data_ptr, e.data_size);
	check_int(ivalue, 1000000);
	
	free(buffer_ptr);
}
static int
demux_mkv_read_info (FILE *s, mkv_demuxer_t *mkv_d)
{
  uint64_t length, l;
  int il;
  uint64_t tc_scale = 1000000;
  long double duration = 0.;

  length = ebml_read_length (s, NULL);
  while (length > 0)
    {
      switch (ebml_read_id (s, &il))
        {
        case MATROSKA_ID_TIMECODESCALE:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              return 1;
            tc_scale = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + timecode scale: %"PRIu64"\n",
                    tc_scale);
            break;
          }

        case MATROSKA_ID_DURATION:
          {
            long double num = ebml_read_float (s, &l);
            if (num == EBML_FLOAT_INVALID)
              return 1;
            duration = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + duration: %.3Lfs\n",
                    duration * tc_scale / 1000000000.0);
            break;
          }

        default:
          ebml_read_skip (s, &l);
          break;
        }
      length -= l + il;
    }
  mkv_d->tc_scale = tc_scale;
  mkv_d->duration = duration * tc_scale / 1000000000.0;
  return 0;
}
/*
 * Read an EBML header.
 */
char *ebml_read_header(stream_t *s, int *version)
{
    uint64_t length, l, num;
    uint32_t id;
    char *str = NULL;

    if (ebml_read_master(s, &length) != EBML_ID_HEADER)
        return 0;

    if (version)
        *version = 1;

    while (length > 0) {
        id = ebml_read_id(s, NULL);
        if (id == EBML_ID_INVALID)
            return NULL;
        length -= 2;

        switch (id) {
            /* is our read version uptodate? */
        case EBML_ID_EBMLREADVERSION:
            num = ebml_read_uint(s, &l);
            if (num != EBML_VERSION)
                return NULL;
            break;

            /* we only handle 8 byte lengths at max */
        case EBML_ID_EBMLMAXSIZELENGTH:
            num = ebml_read_uint(s, &l);
            if (num != sizeof(uint64_t))
                return NULL;
            break;

            /* we handle 4 byte IDs at max */
        case EBML_ID_EBMLMAXIDLENGTH:
            num = ebml_read_uint(s, &l);
            if (num != sizeof(uint32_t))
                return NULL;
            break;

        case EBML_ID_DOCTYPE:
            str = ebml_read_ascii(s, &l);
            if (str == NULL)
                return NULL;
            break;

        case EBML_ID_DOCTYPEREADVERSION:
            num = ebml_read_uint(s, &l);
            if (num == EBML_UINT_INVALID)
                return NULL;
            if (version)
                *version = num;
            break;

            /* we ignore these two, they don't tell us anything we care about */
        case EBML_ID_VOID:
        case EBML_ID_EBMLVERSION:
        case EBML_ID_DOCTYPEVERSION:
        default:
            if (ebml_read_skip(s, &l))
                return NULL;
            break;
        }
        length -= l;
    }

    return str;
}
Exemple #5
0
int ebml_check_header(ebml_parser_t *ebml) {
  uint32_t next_level;
  ebml_elem_t master;

  if (!ebml_read_elem_head(ebml, &master)) {
    xprintf(ebml->xine, XINE_VERBOSITY_LOG,
            "ebml: invalid master element\n");
    return 0;
  }

  if (master.id != EBML_ID_EBML) {
    xprintf(ebml->xine, XINE_VERBOSITY_LOG,
            "ebml: invalid master element\n");
    return 0;
  }

  if (!ebml_read_master (ebml, &master))
    return 0;

  next_level = 1;
  while (next_level == 1) {
    ebml_elem_t elem;

    if (!ebml_read_elem_head(ebml, &elem))
      return 0;

    switch (elem.id) {
      case EBML_ID_EBMLVERSION: {
        uint64_t num;

        if (!ebml_read_uint (ebml, &elem, &num))
          return 0;
        lprintf("ebml_version: %" PRIu64 "\n", num);
        ebml->version = num;
        break;
      }

      case EBML_ID_EBMLREADVERSION: {
        uint64_t num;

        if (!ebml_read_uint (ebml, &elem, &num))
          return 0;
        lprintf("ebml_read_version: %" PRIu64 "\n", num);
        if (num != EBML_VERSION)
          return 0;
        ebml->read_version = num;
        break;
      }

      case EBML_ID_EBMLMAXIDLENGTH: {
        uint64_t num;

        if (!ebml_read_uint (ebml, &elem, &num))
          return 0;
        lprintf("ebml_max_id_length: %" PRIu64 "\n", num);
        ebml->max_id_len = num;
        break;
      }

      case EBML_ID_EBMLMAXSIZELENGTH: {
        uint64_t num;

        if (!ebml_read_uint (ebml, &elem, &num))
          return 0;
        lprintf("ebml_max_size_length: %" PRIu64 "\n", num);
        ebml->max_size_len = num;
        break;
      }

      case EBML_ID_DOCTYPE: {
        char *text = ebml_alloc_read_ascii (ebml, &elem);
        if (!text)
          return 0;

        lprintf("doctype: %s\n", text);
        if (ebml->doctype)
          free (ebml->doctype);
        ebml->doctype = text;
        break;
      }

      case EBML_ID_DOCTYPEVERSION: {
        uint64_t num;

        if (!ebml_read_uint (ebml, &elem, &num))
          return 0;
        lprintf("doctype_version: %" PRIu64 "\n", num);
        ebml->doctype_version = num;
        break;
      }

      case EBML_ID_DOCTYPEREADVERSION: {
        uint64_t num;

        if (!ebml_read_uint (ebml, &elem, &num))
          return 0;
        lprintf("doctype_read_version: %" PRIu64 "\n", num);
        ebml->doctype_read_version = num;
        break;
      }

      default:
        xprintf(ebml->xine, XINE_VERBOSITY_LOG,
                "ebml: Unknown data type 0x%x in EBML header (ignored)\n", elem.id);
	ebml_skip(ebml, &elem);
    }
    next_level = ebml_get_next_level(ebml, &elem);
  }

  return 1;
}
static int
demux_mkv_read_trackentry (FILE *s, mkv_demuxer_t *mkv_d)
{
  mkv_track_t *track;
  uint64_t len, length, l;
  int il;

  track = (mkv_track_t *)calloc (1, sizeof (*track));
  /* set default values */
  track->default_track = 1;
  track->name = 0;
  track->language = strdup("eng");

  len = length = ebml_read_length (s, &il);
  len += il;
  while (length > 0)
    {
      switch (ebml_read_id (s, &il))
        {
        case MATROSKA_ID_TRACKNUMBER:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              goto err_out;
            track->tnum = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Track number: %u\n",
                    track->tnum);
            break;
          }

        case MATROSKA_ID_TRACKNAME:
          {
            track->name = ebml_read_utf8 (s, &l);
            if (track->name == NULL)
              goto err_out;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Name: %s\n",
                    track->name);
            break;
          }

        case MATROSKA_ID_TRACKTYPE:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              goto err_out;
            track->type = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Track type: ");
            switch (track->type)
              {
              case MATROSKA_TRACK_AUDIO:
                mp_msg (MSGT_DEMUX, MSGL_V, "Audio\n");
                break;
              case MATROSKA_TRACK_VIDEO:
                mp_msg (MSGT_DEMUX, MSGL_V, "Video\n");
                break;
              case MATROSKA_TRACK_SUBTITLE:
                mp_msg (MSGT_DEMUX, MSGL_V, "Subtitle\n");
                break;
              default:
                mp_msg (MSGT_DEMUX, MSGL_V, "unknown\n");
                break;
            }
            break;
          }

        case MATROSKA_ID_TRACKAUDIO:
          mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Audio track\n");
          l = demux_mkv_read_trackaudio (s, track);
          if (l == 0)
            goto err_out;
          break;

        case MATROSKA_ID_TRACKVIDEO:
          mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Video track\n");
          l = demux_mkv_read_trackvideo (s, track);
          if (l == 0)
            goto err_out;
          break;

        case MATROSKA_ID_CODECID:
          track->codec_id = ebml_read_ascii (s, &l);
          if (track->codec_id == NULL)
            goto err_out;
          if (!strcmp (track->codec_id, MKV_V_MSCOMP) ||
              !strcmp (track->codec_id, MKV_A_ACM))
            track->ms_compat = 1;
          else if (!strcmp (track->codec_id, MKV_S_VOBSUB))
            track->subtitle_type = MATROSKA_SUBTYPE_VOBSUB;
          else if (!strcmp (track->codec_id, MKV_S_TEXTSSA)
                   || !strcmp (track->codec_id, MKV_S_TEXTASS)
                   || !strcmp (track->codec_id, MKV_S_SSA)
                   || !strcmp (track->codec_id, MKV_S_ASS))
            {
              track->subtitle_type = MATROSKA_SUBTYPE_SSA;
            }
          else if (!strcmp (track->codec_id, MKV_S_TEXTASCII))
            track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
          if (!strcmp (track->codec_id, MKV_S_TEXTUTF8))
            {
              track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
            }
          mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Codec ID: %s\n",
                  track->codec_id);
          break;

        case MATROSKA_ID_CODECPRIVATE:
          {
            int x;
            uint64_t num = ebml_read_length (s, &x);
	    // audit: cheap guard against overflows later..
	    if (num > SIZE_MAX - 1000)
              goto err_out;
            l = x + num;
            track->private_data = malloc (num + AV_LZO_INPUT_PADDING);
            if (read_data(s, track->private_data, num) != (size_t) num)
              goto err_out;
            track->private_size = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + CodecPrivate, length "
                    "%u\n", track->private_size);
			if( track->type == MATROSKA_TRACK_VIDEO &&
					!strcmp(track->codec_id,MKV_V_MPEG4_AVC)
			  )
			{
				unsigned char*  ptr, *hdr;
				int write_len=0;
				int avc1_header_size = 0;

				ptr = (unsigned char *)track->private_data + 7; //skip 01 64 00 29 FF E1 00 and seek to first header len pos.

				unsigned char *avc1_header = (unsigned char *)malloc (track->private_size + AV_LZO_INPUT_PADDING);
				hdr = avc1_header;

				write_len = *ptr++; //get first header len

				hdr[0] = hdr[1] = hdr[2] = 0;
				hdr[3] = (unsigned char)write_len;
				hdr += 4;

				memcpy(hdr, ptr, write_len);
				hdr += write_len;
				ptr += write_len;

				avc1_header_size += 4 + write_len;

				mp_msg(MSGT_DEMUX, MSGL_V, "1write_len[%d]\n",write_len);//SkyMedi_Vincent

				ptr += 2;   //skip 01 00 and seek to second header len pos.
				write_len = *ptr++; //get second header len

				hdr[0] = hdr[1] = hdr[2] = 0;
				hdr[3] = (unsigned char)write_len;
				hdr += 4;

				memcpy(hdr, ptr, write_len);

				avc1_header_size += 4 + write_len;

				mp_msg(MSGT_DEMUX, MSGL_V, "2write_len[%d]\n",write_len);//SkyMedi_Vincent
				mp_msg(MSGT_DEMUX, MSGL_V, "avc1_header_size = %d\n", avc1_header_size);
				{
					int i = 0;
					for( i = 0 ; i< avc1_header_size; i++)
						mp_msg(MSGT_DEMUX, MSGL_V, "%02X ", avc1_header[i]);
					mp_msg(MSGT_DEMUX, MSGL_V, "\n");
				}

				if (!check_avc1_sps_bank0(avc1_header+5, avc1_header_size-5))
					goto err_out;

				free(avc1_header);
			}
            break;
          }

        case MATROSKA_ID_TRACKLANGUAGE:
          free(track->language);
          track->language = ebml_read_utf8 (s, &l);
          if (track->language == NULL)
            goto err_out;
          mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Language: %s\n",
                  track->language);
          break;

        case MATROSKA_ID_TRACKFLAGDEFAULT:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              goto err_out;
            track->default_track = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Default flag: %u\n",
                    track->default_track);
            break;
          }

        case MATROSKA_ID_TRACKDEFAULTDURATION:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              goto err_out;
            if (num == 0)
              mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Default duration: 0");
            else
              {
                track->v_frate = 1000000000.0 / num;
                track->default_duration = num / 1000000000.0;
                mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |  + Default duration: "
                        "%.3fms ( = %.3f fps)\n",num/1000000.0,track->v_frate);
              }
            break;
          }

        case MATROSKA_ID_TRACKENCODINGS:
          l = demux_mkv_read_trackencodings (s, track);
          if (l == 0)
            goto err_out;
          break;

        default:
          ebml_read_skip (s, &l);
          break;
        }
      length -= l + il;
    }

  mkv_d->tracks[mkv_d->num_tracks++] = track;
  return len;

err_out:
  demux_mkv_free_trackentry(track);
  return 0;
}
static int
demux_mkv_read_trackencodings (FILE *s, mkv_track_t *track)
{
  mkv_content_encoding_t *ce, e;
  uint64_t len, length, l;
  int il, n;

  ce = (mkv_content_encoding_t *)malloc (sizeof (*ce));
  n = 0;

  len = length = ebml_read_length (s, &il);
  if (len == EBML_UINT_INVALID)
	  goto err_out;
  len += il;
  while (length > 0)
    {
      switch (ebml_read_id (s, &il))
        {
        case MATROSKA_ID_CONTENTENCODING:
          {
            uint64_t len;
            int i;

            memset (&e, 0, sizeof (e));
            e.scope = 1;

            len = ebml_read_length (s, &i);
	    if (len == EBML_UINT_INVALID)
		    goto err_out;
            l = len + i;

            while (len > 0)
              {
                uint64_t num, ll;
                int iil;

                switch (ebml_read_id (s, &iil))
                  {
                  case MATROSKA_ID_CONTENTENCODINGORDER:
                    num = ebml_read_uint (s, &ll);
                    if (num == EBML_UINT_INVALID)
                      goto err_out;
                    e.order = num;
                    break;

                  case MATROSKA_ID_CONTENTENCODINGSCOPE:
                    num = ebml_read_uint (s, &ll);
                    if (num == EBML_UINT_INVALID)
                      goto err_out;
                    e.scope = num;
                    break;

                  case MATROSKA_ID_CONTENTENCODINGTYPE:
                    num = ebml_read_uint (s, &ll);
                    if (num == EBML_UINT_INVALID)
                      goto err_out;
                    e.type = num;
                    break;

                  case MATROSKA_ID_CONTENTCOMPRESSION:
                    {
                      uint64_t le;

                      le = ebml_read_length (s, &i);
		      if (le == EBML_UINT_INVALID)
			      goto err_out;
                      ll = le + i;

                      while (le > 0)
                        {
                          uint64_t lll;
                          int iiil;

                          switch (ebml_read_id (s, &iiil))
                            {
                            case MATROSKA_ID_CONTENTCOMPALGO:
                              num = ebml_read_uint (s, &lll);
                              if (num == EBML_UINT_INVALID)
                                goto err_out;
                              e.comp_algo = num;
                              break;

                            case MATROSKA_ID_CONTENTCOMPSETTINGS:
                              lll = ebml_read_length (s, &i);
			      if (lll == EBML_UINT_INVALID)
                                goto err_out;
                              e.comp_settings = (uint8_t*)malloc (lll);
                              read_data(s, e.comp_settings, lll);
                              e.comp_settings_len = lll;
                              lll += i;
                              break;

                            default:
                              ebml_read_skip (s, &lll);
                              break;
                            }
                          le -= lll + iiil;
                        }

                      if (e.type == 1)
                        {
                          mp_msg(MSGT_DEMUX, MSGL_WARN,
                                 MSGTR_MPDEMUX_MKV_TrackEncrypted, track->tnum);
                        }
                      else if (e.type != 0)
                        {
                          mp_msg(MSGT_DEMUX, MSGL_WARN,
                                 MSGTR_MPDEMUX_MKV_UnknownContentEncoding, track->tnum);
                        }

                      if (e.comp_algo != 0 && e.comp_algo != 2)
                        {
                          mp_msg (MSGT_DEMUX, MSGL_WARN,
                                  MSGTR_MPDEMUX_MKV_UnknownCompression,
                                  track->tnum, e.comp_algo);
                        }
#if !CONFIG_ZLIB
                      else if (e.comp_algo == 0)
                        {
                          mp_msg (MSGT_DEMUX, MSGL_WARN,
                                  MSGTR_MPDEMUX_MKV_ZlibCompressionUnsupported,
                                  track->tnum);
                        }
#endif

                      break;
                    }

                  default:
                    ebml_read_skip (s, &ll);
                    break;
                  }
                len -= ll + iil;
              }
            for (i=0; i<n; i++)
              if (e.order <= ce[i].order)
                break;
            ce = (mkv_content_encoding_t*)realloc (ce, (n+1) *sizeof (*ce));
            memmove (ce+i+1, ce+i, (n-i) * sizeof (*ce));
            memcpy (ce+i, &e, sizeof (e));
            n++;
            break;
          }

        default:
          ebml_read_skip (s, &l);
          break;
        }

      length -= l + il;
    }

  track->encodings = ce;
  track->num_encodings = n;
  return len;

err_out:
  demux_mkv_free_encodings(ce, n);
  return 0;
}
static int
demux_mkv_read_block(FILE *s, mkv_demuxer_t *mkv_d)
{
	uint64_t length, l;
	int il, tmp;
	uint64_t block_duration = 0,  block_length = 0;
	int64_t block_bref = 0, block_fref = 0;
	uint8_t *block = NULL;

	length = ebml_read_length (s, NULL);
	while (length > 0)
	{
		switch (ebml_read_id (s, &il))
		{
			case MATROSKA_ID_BLOCKDURATION:
				//puts("MATROSKA_ID_BLOCKDURATION");
				block_duration = ebml_read_uint (s, &l);
				if (block_duration == EBML_UINT_INVALID) {
					if(block)
						free(block);
					return 0;
				}
				block_duration *= mkv_d->tc_scale / 1000000.0;
				break;
			case MATROSKA_ID_BLOCK:
				//puts("MATROSKA_ID_BLOCK");
				block_length = ebml_read_length (s, &tmp);
				if(block)
					free(block);
				if (block_length > SIZE_MAX - AV_LZO_INPUT_PADDING) return 0;
				block = (uint8_t *)malloc (block_length + AV_LZO_INPUT_PADDING);
				if (!block)
				{
					return 0;
				}
				if (fread(block, 1, (size_t)block_length, s) != (size_t) block_length)
				{
					if(block)
						free(block);
					return 0;
				}
				l = tmp + block_length;
				break;
			case MATROSKA_ID_REFERENCEBLOCK:
				//puts("MATROSKA_ID_REFERENCEBLOCK");
				{
					int64_t num = ebml_read_int (s, &l);
					if (num == EBML_INT_INVALID) {
						if(block)
							free(block);
						return 0;
					}
					if (num <= 0)
						block_bref = num;
					else
						block_fref = num;
					break;
				}
			case EBML_ID_INVALID:
				//puts("EBML_ID_INVALID");
				if(block)
					free(block);
				return 0;
			default:
				ebml_read_skip (s, &l);
				break;
		}
		length -= l + il;

		if (block)
		{
			handle_block (mkv_d, block, block_length,
					block_duration, block_bref, block_fref, 0);
			free (block);
			block = NULL;
		}
	}
	return 0;
}
static int
demux_mkv_read_trackvideo (FILE *s, mkv_track_t *track)
{
  uint64_t len, length, l;
  int il;

  len = length = ebml_read_length (s, &il);
  len += il;
  while (length > 0)
    {
      switch (ebml_read_id (s, &il))
        {
        case MATROSKA_ID_VIDEOFRAMERATE:
          {
            long double num = ebml_read_float (s, &l);
            if (num == EBML_FLOAT_INVALID)
              return 0;
            track->v_frate = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Frame rate: %f\n",
                    track->v_frate);
            if (track->v_frate > 0)
              track->default_duration = 1 / track->v_frate;
            break;
          }

        case MATROSKA_ID_VIDEODISPLAYWIDTH:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              return 0;
            track->v_dwidth = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Display width: %u\n",
                    track->v_dwidth);
            break;
          }

        case MATROSKA_ID_VIDEODISPLAYHEIGHT:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              return 0;
            track->v_dheight = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Display height: %u\n",
                    track->v_dheight);
            break;
          }

        case MATROSKA_ID_VIDEOPIXELWIDTH:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              return 0;
            track->v_width = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Pixel width: %u\n",
                    track->v_width);
            break;
          }

        case MATROSKA_ID_VIDEOPIXELHEIGHT:
          {
            uint64_t num = ebml_read_uint (s, &l);
            if (num == EBML_UINT_INVALID)
              return 0;
            track->v_height = num;
            mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |   + Pixel height: %u\n",
                    track->v_height);
            break;
          }

        default:
            ebml_read_skip (s, &l);
            break;
        }
      length -= l + il;
    }
  return len;
}