static int demux_mkv_read_cluster(FILE *s, mkv_demuxer_t *mkv_d) { uint64_t length, l; int il; length = ebml_read_length (s, NULL); while (length > 0) { switch (ebml_read_id (s, &il)) { case MATROSKA_ID_BLOCKGROUP: demux_mkv_read_block(s, mkv_d); return 1; break; case EBML_ID_INVALID: return 0; default: ebml_read_skip (s, &l); break; } length -= l + il; } return 1; }
static int demux_mkv_read_tracks (FILE *s, mkv_demuxer_t *mkv_d) { uint64_t length, l; int il; mkv_d->tracks = (mkv_track_t**)malloc (sizeof (*mkv_d->tracks)); mkv_d->num_tracks = 0; length = ebml_read_length (s, NULL); while (length > 0) { switch (ebml_read_id (s, &il)) { case MATROSKA_ID_TRACKENTRY: mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + a track...\n"); mkv_d->tracks = (mkv_track_t**)realloc (mkv_d->tracks, (mkv_d->num_tracks+1) *sizeof (*mkv_d->tracks)); l = demux_mkv_read_trackentry (s, mkv_d); if (l == 0) return 1; break; default: ebml_read_skip (s, &l); break; } length -= l + il; } return 0; }
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; }
/* * Read the next element, but only the header. The contents * are supposed to be sub-elements which can be read separately. */ uint32_t ebml_read_master(stream_t *s, uint64_t *length) { uint64_t len; uint32_t id; id = ebml_read_id(s, NULL); if (id == EBML_ID_INVALID) return id; len = ebml_read_length(s, NULL); if (len == EBML_UINT_INVALID) return EBML_ID_INVALID; if (length) *length = len; return id; }
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; }
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; }
int MKV_Parser(FILE *fp, FileInfo *finfo) { int nRet = 0, cont = 0, ii, jj; int is_hw_notsupport = 0; nRet = mkv_check_file(fp, finfo); mkv_track_t *track; if (nRet == 0) return nRet; mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n"); if (ebml_read_id (fp, NULL) != MATROSKA_ID_SEGMENT) { mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n"); return 0; } ebml_read_length (fp, NULL); /* return bytes number until EOF */ mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n"); mkv_demuxer_t *mkv_d = (mkv_demuxer_t *)calloc (1, sizeof (mkv_demuxer_t)); finfo->priv = mkv_d; mkv_d->tc_scale = 1000000; mkv_d->segment_start = read_tell (fp); mkv_d->parsed_cues = (off_t *)malloc (sizeof (off_t)); mkv_d->parsed_seekhead = (off_t *)malloc (sizeof (off_t)); while (!cont) { switch (ebml_read_id (fp, NULL)) { case MATROSKA_ID_INFO: mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |+ segment information...\n"); cont = demux_mkv_read_info (fp, mkv_d); break; case MATROSKA_ID_TRACKS: mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |+ segment tracks...\n"); cont = demux_mkv_read_tracks (fp, mkv_d); break; case MATROSKA_ID_CUES: case MATROSKA_ID_TAGS: case MATROSKA_ID_SEEKHEAD: case MATROSKA_ID_CHAPTERS: case MATROSKA_ID_ATTACHMENTS: ebml_read_skip (fp, NULL); break; case MATROSKA_ID_CLUSTER: mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are " "parsed completely :)\n"); demux_mkv_read_cluster(fp, mkv_d); cont = 1; break; default: cont = 1; case EBML_ID_VOID: ebml_read_skip (fp, NULL); break; } } /* select video track */ track = NULL; /* search for a video track that has the 'default' flag set */ /* for (ii=0; ii<mkv_d->num_tracks; ii++) if (mkv_d->tracks[ii]->type == MATROSKA_TRACK_VIDEO && mkv_d->tracks[ii]->default_track) { if (mkv_d->tracks[ii]->hw_notsupport == 1) { is_hw_notsupport = 1; break; } else { track = mkv_d->tracks[ii]; break; } } */ if (track == NULL) { int comp_algo_support = 1; /* no track has the 'default' flag set */ /* let's take the first video track */ for (ii=0; ii<mkv_d->num_tracks; ii++) { if (mkv_d->tracks[ii]->type == MATROSKA_TRACK_VIDEO) { if(mkv_d->tracks[ii]->hw_notsupport == 1) { is_hw_notsupport = 1; } else { track = mkv_d->tracks[ii]; for (jj=0; jj < track->num_encodings; jj++) { mp_msg(MSGT_DEMUX, MSGL_V, "num_encodings: %d, comp algo: %d\n", track->num_encodings, track->encodings->comp_algo); if (track->encodings->comp_algo != 0 && track->encodings->comp_algo != 2 &&track->encodings->comp_algo != 3) { printf("MKV: Video track %d has been compressed\n", track->tnum); comp_algo_support = 0; } } if (comp_algo_support == 0) continue; else { comp_algo_support = 1; break; } } } } if (comp_algo_support == 0) { goto mkv_parse_err; } } if (track != NULL) { if (demux_mkv_open_video(finfo, track) == 0) { finfo->bVideo = 1; finfo->FileDuration = mkv_d->duration; nRet = 1; } } if ((track == NULL) && (is_hw_notsupport == 1)) { // the only video is not support. } else { /* select audio track */ track = NULL; /* search for an audio track that has the 'default' flag set */ /* for (ii=0; ii < mkv_d->num_tracks; ii++) { if (mkv_d->tracks[ii]->type == MATROSKA_TRACK_AUDIO && mkv_d->tracks[ii]->default_track) { track = mkv_d->tracks[ii]; break; } } */ if (track == NULL) { /* no track has the 'default' flag set */ /* let's take the first audio track */ for (ii=0; ii < mkv_d->num_tracks; ii++) { if (mkv_d->tracks[ii]->type == MATROSKA_TRACK_AUDIO) { track = mkv_d->tracks[ii]; int comp_algo_support = 1; for (jj=0; jj < track->num_encodings; jj++) { mp_msg(MSGT_DEMUX, MSGL_V, "num_encodings: %d, comp algo: %d\n", track->num_encodings, track->encodings->comp_algo); if (track->encodings->comp_algo != 0 && track->encodings->comp_algo != 2 &&track->encodings->comp_algo != 3) { printf("MKV: Audio track %d has been compressed\n", track->tnum); comp_algo_support = 0; } } if (demux_mkv_open_audio(finfo, track) == 0) { finfo->bAudio = 1; finfo->AudioDuration = mkv_d->duration; finfo->AudioType = track->a_formattag; if (comp_algo_support == 1) { nRet = 1; if (check_audio_type(track->a_formattag, track->a_channels, finfo->hw_a_flag) == 1) { break; } } else { nRet = 0; } } else { nRet = 0; } } } } } mkv_parse_err: if (mkv_d != NULL) { demux_close_mkv(mkv_d); finfo->priv = NULL; } return nRet; }