matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size, int64_t pos, uint64_t cluster_time, uint64_t duration, int is_keyframe, int is_bframe) { int res = 0; int track; AVStream *st; AVPacket *pkt; uint8_t *origdata = data; int16_t block_time; uint32_t *lace_size = NULL; int n, flags, laces = 0; uint64_t num; int stream_index; /* first byte(s): tracknum */ if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); av_free(origdata); return res; } data += n; size -= n; /* fetch track from num */ track = matroska_find_track_by_num(matroska, num); if (size <= 3 || track < 0 || track >= matroska->num_tracks) { av_log(matroska->ctx, AV_LOG_INFO, "Invalid stream %d or size %u\n", track, size); av_free(origdata); return res; } stream_index = matroska->tracks[track]->stream_index; if (stream_index < 0 || stream_index >= matroska->ctx->nb_streams) { av_free(origdata); return res; } st = matroska->ctx->streams[stream_index]; if (st->discard >= AVDISCARD_ALL) { av_free(origdata); return res; } if (duration == AV_NOPTS_VALUE) duration = matroska->tracks[track]->default_duration / matroska->time_scale; /* block_time (relative to cluster time) */ block_time = AV_RB16(data); data += 2; flags = *data++; size -= 3; if (is_keyframe == -1) is_keyframe = flags & 0x80 ? PKT_FLAG_KEY : 0; if (matroska->skip_to_keyframe) { if (!is_keyframe || st != matroska->skip_to_stream) { av_free(origdata); return res; } matroska->skip_to_keyframe = 0; } switch ((flags & 0x06) >> 1) { case 0x0: /* no lacing */ laces = 1; lace_size = av_mallocz(sizeof(int)); lace_size[0] = size; break; case 0x1: /* xiph lacing */ case 0x2: /* fixed-size lacing */ case 0x3: /* EBML lacing */ assert(size>0); // size <=3 is checked before size-=3 above laces = (*data) + 1; data += 1; size -= 1; lace_size = av_mallocz(laces * sizeof(int)); switch ((flags & 0x06) >> 1) { case 0x1: /* xiph lacing */ { uint8_t temp; uint32_t total = 0; for (n = 0; res == 0 && n < laces - 1; n++) { while (1) { if (size == 0) { res = -1; break; } temp = *data; lace_size[n] += temp; data += 1; size -= 1; if (temp != 0xff) break; } total += lace_size[n]; } lace_size[n] = size - total; break; } case 0x2: /* fixed-size lacing */ for (n = 0; n < laces; n++) lace_size[n] = size / laces; break; case 0x3: /* EBML lacing */ { uint32_t total; n = matroska_ebmlnum_uint(data, size, &num); if (n < 0) { av_log(matroska->ctx, AV_LOG_INFO, "EBML block data error\n"); break; } data += n; size -= n; total = lace_size[0] = num; for (n = 1; res == 0 && n < laces - 1; n++) { int64_t snum; int r; r = matroska_ebmlnum_sint (data, size, &snum); if (r < 0) { av_log(matroska->ctx, AV_LOG_INFO, "EBML block data error\n"); break; } data += r; size -= r; lace_size[n] = lace_size[n - 1] + snum; total += lace_size[n]; } lace_size[n] = size - total; break; } } break; } if (res == 0) { uint64_t timecode = AV_NOPTS_VALUE; if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time)) timecode = cluster_time + block_time; for (n = 0; n < laces; n++) { if (st->codec->codec_id == CODEC_ID_RA_288 || st->codec->codec_id == CODEC_ID_COOK || st->codec->codec_id == CODEC_ID_ATRAC3) { MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)matroska->tracks[track]; int a = st->codec->block_align; int sps = audiotrack->sub_packet_size; int cfs = audiotrack->coded_framesize; int h = audiotrack->sub_packet_h; int y = audiotrack->sub_packet_cnt; int w = audiotrack->frame_size; int x; if (!audiotrack->pkt_cnt) { if (st->codec->codec_id == CODEC_ID_RA_288) for (x=0; x<h/2; x++) memcpy(audiotrack->buf+x*2*w+y*cfs, data+x*cfs, cfs); else for (x=0; x<w/sps; x++) memcpy(audiotrack->buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps); if (++audiotrack->sub_packet_cnt >= h) { audiotrack->sub_packet_cnt = 0; audiotrack->pkt_cnt = h*w / a; } } while (audiotrack->pkt_cnt) { pkt = av_mallocz(sizeof(AVPacket)); av_new_packet(pkt, a); memcpy(pkt->data, audiotrack->buf + a * (h*w / a - audiotrack->pkt_cnt--), a); pkt->pos = pos; pkt->stream_index = stream_index; matroska_queue_packet(matroska, pkt); } } else { int result, offset = 0, ilen, olen, pkt_size = lace_size[n]; uint8_t *pkt_data = data; if (matroska->tracks[track]->encoding_scope & 1) { switch (matroska->tracks[track]->encoding_algo) { case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP: offset = matroska->tracks[track]->encoding_settings_len; break; case MATROSKA_TRACK_ENCODING_COMP_LZO: pkt_data = NULL; do { ilen = lace_size[n]; olen = pkt_size *= 3; pkt_data = av_realloc(pkt_data, pkt_size+LZO_OUTPUT_PADDING); result = lzo1x_decode(pkt_data, &olen, data, &ilen); } while (result==LZO_OUTPUT_FULL && pkt_size<10000000); if (result) { continue; } pkt_size -= olen; break; #ifdef CONFIG_ZLIB case MATROSKA_TRACK_ENCODING_COMP_ZLIB: { z_stream zstream = {0}; pkt_data = NULL; if (inflateInit(&zstream) != Z_OK) continue; zstream.next_in = data; zstream.avail_in = lace_size[n]; do { pkt_size *= 3; pkt_data = av_realloc(pkt_data, pkt_size); zstream.avail_out = pkt_size - zstream.total_out; zstream.next_out = pkt_data + zstream.total_out; result = inflate(&zstream, Z_NO_FLUSH); } while (result==Z_OK && pkt_size<10000000); pkt_size = zstream.total_out; inflateEnd(&zstream); if (result != Z_STREAM_END) { continue; } break; } #endif #ifdef CONFIG_BZLIB case MATROSKA_TRACK_ENCODING_COMP_BZLIB: { bz_stream bzstream = {0}; pkt_data = NULL; if (BZ2_bzDecompressInit(&bzstream, 0, 0) != BZ_OK) continue; bzstream.next_in = data; bzstream.avail_in = lace_size[n]; do { pkt_size *= 3; pkt_data = av_realloc(pkt_data, pkt_size); bzstream.avail_out = pkt_size - bzstream.total_out_lo32; bzstream.next_out = pkt_data + bzstream.total_out_lo32; result = BZ2_bzDecompress(&bzstream); } while (result==BZ_OK && pkt_size<10000000); pkt_size = bzstream.total_out_lo32; BZ2_bzDecompressEnd(&bzstream); if (result != BZ_STREAM_END) { continue; } break; } #endif } } pkt = av_mallocz(sizeof(AVPacket)); /* XXX: prevent data copy... */ if (av_new_packet(pkt, pkt_size+offset) < 0) { av_free(pkt); res = AVERROR(ENOMEM); n = laces-1; break; } if (offset) memcpy (pkt->data, matroska->tracks[track]->encoding_settings, offset); memcpy (pkt->data+offset, pkt_data, pkt_size); if (n == 0) pkt->flags = is_keyframe; pkt->stream_index = stream_index; pkt->pts = timecode; pkt->pos = pos; pkt->duration = duration; matroska_queue_packet(matroska, pkt); } if (timecode != AV_NOPTS_VALUE) timecode = duration ? timecode + duration : AV_NOPTS_VALUE; data += lace_size[n]; } } av_free(lace_size); av_free(origdata); return res; }