+static int read_gab2_sub(AVStream *st, AVPacket *pkt) {
+ if (!strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data+5) == 2) {
+ uint8_t desc[256];
+ int score = AVPROBE_SCORE_MAX / 2, ret;
+ AVIStream *ast = st->priv_data;
+ AVInputFormat *sub_demuxer;
+ AVRational time_base;
+ AVIOContext *pb = avio_alloc_context( pkt->data + 7,
+ pkt->size - 7,
+ 0, NULL, NULL, NULL, NULL);
+ AVProbeData pd;
+ unsigned int desc_len = avio_rl32(pb);
+
+ if (desc_len > pb->buf_end - pb->buf_ptr)
+ goto error;
+
+ ret = avio_get_str16le(pb, desc_len, desc, sizeof(desc));
+ avio_skip(pb, desc_len - ret);
+ if (*desc)
+ av_dict_set(&st->metadata, "title", desc, 0);
+
+ avio_rl16(pb); /* flags? */
+ avio_rl32(pb); /* data size */
+
+ pd = (AVProbeData) { .buf = pb->buf_ptr, .buf_size = pb->buf_end - pb->buf_ptr };
+ if (!(sub_demuxer = av_probe_input_format2(&pd, 1, &score)))
+ goto error;
+
+ if (!(ast->sub_ctx = avformat_alloc_context()))
+ goto error;
+
+ ast->sub_ctx->pb = pb;
+ if (!avformat_open_input(&ast->sub_ctx, "", sub_demuxer, NULL)) {
+ ff_read_packet(ast->sub_ctx, &ast->sub_pkt);
+ *st->codec = *ast->sub_ctx->streams[0]->codec;
+ ast->sub_ctx->streams[0]->codec->extradata = NULL;
+ time_base = ast->sub_ctx->streams[0]->time_base;
+ avpriv_set_pts_info(st, 64, time_base.num, time_base.den);
+ }
+ ast->sub_buffer = pkt->data;
+ memset(pkt, 0, sizeof(*pkt));
+ return 1;
+error:
+ av_freep(&pb);
+ }
+ return 0;
+}
+
+static AVStream *get_subtitle_pkt(AVFormatContext *s, AVStream *next_st,
+ AVPacket *pkt)
+{
+ AVIStream *ast, *next_ast = next_st->priv_data;
+ int64_t ts, next_ts, ts_min = INT64_MAX;
+ AVStream *st, *sub_st = NULL;
+ int i;
+
+ next_ts = av_rescale_q(next_ast->frame_offset, next_st->time_base,
+ AV_TIME_BASE_Q);
+
+ for (i=0; i<s->nb_streams; i++) {
+ st = s->streams[i];
+ ast = st->priv_data;
+ if (st->discard < AVDISCARD_ALL && ast && ast->sub_pkt.data) {
+ ts = av_rescale_q(ast->sub_pkt.dts, st->time_base, AV_TIME_BASE_Q);
+ if (ts <= next_ts && ts < ts_min) {
+ ts_min = ts;
+ sub_st = st;
+ }
+ }
+ }
+
+ if (sub_st) {
+ ast = sub_st->priv_data;
+ *pkt = ast->sub_pkt;
+ pkt->stream_index = sub_st->index;
+ if (ff_read_packet(ast->sub_ctx, &ast->sub_pkt) < 0)
+ ast->sub_pkt.data = NULL;
+ }
+ return sub_st;
+}
+
+static int get_stream_idx(int *d){
+ if( d[0] >= '0' && d[0] <= '9'
+ && d[1] >= '0' && d[1] <= '9'){
+ return (d[0] - '0') * 10 + (d[1] - '0');
+ }else{
+ return 100; //invalid stream ID
+ }
+}
+
+static int avi_sync(AVFormatContext *s, int exit_early)
+{
+ AVIContext *avi = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int n;
+ unsigned int d[8];
+ unsigned int size;
+ int64_t i, sync;
+
+start_sync:
+ memset(d, -1, sizeof(d));
+ for(i=sync=avio_tell(pb); !pb->eof_reached; i++) {
+ int j;
+
+ for(j=0; j<7; j++)
+ d[j]= d[j+1];
+ d[7]= avio_r8(pb);
+
+ size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24);
+
+ n= get_stream_idx(d+2);
+ av_dlog(s, "%X %X %X %X %X %X %X %X %"PRId64" %u %d\n",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n);
+ if(i + (uint64_t)size > avi->fsize || d[0] > 127)
+ continue;
+
+ //parse ix##
+ if( (d[0] == 'i' && d[1] == 'x' && n < s->nb_streams)
+ //parse JUNK
+ ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K')
+ ||(d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')){
+ avio_skip(pb, size);
+ goto start_sync;
+ }
+
+ //parse stray LIST
+ if(d[0] == 'L' && d[1] == 'I' && d[2] == 'S' && d[3] == 'T'){
+ avio_skip(pb, 4);
+ goto start_sync;
+ }
+
+ n= get_stream_idx(d);
+
+ if(!((i-avi->last_pkt_pos)&1) && get_stream_idx(d+1) < s->nb_streams)
+ continue;
+
+ //detect ##ix chunk and skip
+ if(d[2] == 'i' && d[3] == 'x' && n < s->nb_streams){
+ avio_skip(pb, size);
+ goto start_sync;
+ }
+
+ //parse ##dc/##wb
+ if(n < s->nb_streams){
+ AVStream *st;
+ AVIStream *ast;
+ st = s->streams[n];
+ ast = st->priv_data;
+
+ if(s->nb_streams>=2){
+ AVStream *st1 = s->streams[1];
+ AVIStream *ast1= st1->priv_data;
+ //workaround for broken small-file-bug402.avi
+ if( d[2] == 'w' && d[3] == 'b'
+ && n==0
+ && st ->codec->codec_type == AVMEDIA_TYPE_VIDEO
+ && st1->codec->codec_type == AVMEDIA_TYPE_AUDIO
+ && ast->prefix == 'd'*256+'c'
+ && (d[2]*256+d[3] == ast1->prefix || !ast1->prefix_count)
+ ){
+ n=1;
+ st = st1;
+ ast = ast1;
+ av_log(s, AV_LOG_WARNING, "Invalid stream + prefix combination, assuming audio.\n");
+ }
+ }
+
+
+ if( (st->discard >= AVDISCARD_DEFAULT && size==0)
+ /*|| (st->discard >= AVDISCARD_NONKEY && !(pkt->flags & AV_PKT_FLAG_KEY))*/ //FIXME needs a little reordering
+ || st->discard >= AVDISCARD_ALL){
+ if (!exit_early) {
+ ast->frame_offset += get_duration(ast, size);
+ }
+ avio_skip(pb, size);
+ goto start_sync;
+ }
+
+ if (d[2] == 'p' && d[3] == 'c' && size<=4*256+4) {
+ int k = avio_r8(pb);
+ int last = (k + avio_r8(pb) - 1) & 0xFF;
+
+ avio_rl16(pb); //flags
+
+ for (; k <= last; k++)
+ ast->pal[k] = avio_rb32(pb)>>8;// b + (g << 8) + (r << 16);
+ ast->has_pal= 1;
+ goto start_sync;
+ } else if( ((ast->prefix_count<5 || sync+9 > i) && d[2]<128 && d[3]<128) ||
+ d[2]*256+d[3] == ast->prefix /*||
+ (d[2] == 'd' && d[3] == 'c') ||
+ (d[2] == 'w' && d[3] == 'b')*/) {
+
+ if (exit_early)
+ return 0;
+ if(d[2]*256+d[3] == ast->prefix)
+ ast->prefix_count++;
+ else{
+ ast->prefix= d[2]*256+d[3];
+ ast->prefix_count= 0;
+ }
+
+ avi->stream_index= n;
+ ast->packet_size= size + 8;
+ ast->remaining= size;
+
+ if(size || !ast->sample_size){
+ uint64_t pos= avio_tell(pb) - 8;
+ if(!st->index_entries || !st->nb_index_entries || st->index_entries[st->nb_index_entries - 1].pos < pos){
+ av_add_index_entry(st, pos, ast->frame_offset, size, 0, AVINDEX_KEYFRAME);
+ }
+ }
+ return 0;
+ }
+ }
+ }
+
+ return AVERROR_EOF;
+}
+