static int qcp_probe(AVProbeData *pd) { if (AV_RL32(pd->buf ) == AV_RL32("RIFF") && AV_RL64(pd->buf+8) == AV_RL64("QLCMfmt ")) return AVPROBE_SCORE_MAX; return 0; }
static int asf_header_parser(MMSContext *mms) { uint8_t *p = mms->asf_header; uint8_t *end; int flags, stream_id, real_header_size; mms->stream_num = 0; if (mms->asf_header_size < sizeof(ff_asf_guid) * 2 + 22 || memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) return -1; real_header_size = AV_RL64(p + sizeof(ff_asf_guid)); end = mms->asf_header + real_header_size; p += sizeof(ff_asf_guid) + 14; while(end - p >= sizeof(ff_asf_guid) + 8) { uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid)); if (!chunksize || chunksize > end - p) { dprintf(NULL, "chunksize is exceptional value:%d!\n", chunksize); return -1; } if (!memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) { /* read packet size */ if (end - p > sizeof(ff_asf_guid) * 2 + 68) { mms->asf_packet_len = AV_RL32(p + sizeof(ff_asf_guid) * 2 + 64); if (mms->asf_packet_len <= 0 || mms->asf_packet_len > sizeof(mms->in_buffer)) { dprintf(NULL,"Too large packet len:%d" " may overwrite in_buffer when padding", mms->asf_packet_len); return -1; } } } else if (!memcmp(p, ff_asf_stream_header, sizeof(ff_asf_guid))) { flags = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24); stream_id = flags & 0x7F; //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size, //we can calcuate the packet size by stream_num. //Please see function send_stream_selection_request(). if (mms->stream_num < MAX_STREAMS && 46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) { mms->streams[mms->stream_num].id = stream_id; mms->stream_num++; } else { dprintf(NULL, "Too many streams.\n"); return -1; } } p += chunksize; } return 0; }
/** * From MSDN 2.2.1.4, we learn that ASF data packets over RTP should not * contain any padding. Unfortunately, the header min/max_pktsize are not * updated (thus making min_pktsize invalid). Here, we "fix" these faulty * min_pktsize values in the ASF file header. * @return 0 on success, <0 on failure (currently -1). */ static int rtp_asf_fix_header(uint8_t *buf, int len) { uint8_t *p = buf, *end = buf + len; if (len < sizeof(ff_asf_guid) * 2 + 22 || memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) { return -1; } p += sizeof(ff_asf_guid) + 14; do { uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid)); if (memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) { if (chunksize > end - p) return -1; p += chunksize; continue; } /* skip most of the file header, to min_pktsize */ p += 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2; if (p + 8 <= end && AV_RL32(p) == AV_RL32(p + 4)) { /* and set that to zero */ AV_WL32(p, 0); return 0; } break; } while (end - p >= sizeof(ff_asf_guid) + 8); return -1; }
static int asf_header_parser(MMSContext *mms) { uint8_t *p = mms->asf_header; uint8_t *end; int flags, stream_id; mms->stream_num = 0; if (mms->asf_header_size < sizeof(ff_asf_guid) * 2 + 22 || memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (invalid ASF header, size=%d)\n", mms->asf_header_size); return AVERROR_INVALIDDATA; } end = mms->asf_header + mms->asf_header_size; p += sizeof(ff_asf_guid) + 14; while(end - p >= sizeof(ff_asf_guid) + 8) { uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid)); if (!chunksize || chunksize > end - p) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (header chunksize %"PRId64" is invalid)\n", chunksize); return AVERROR_INVALIDDATA; } if (!memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) { /* read packet size */ if (end - p > sizeof(ff_asf_guid) * 2 + 68) { mms->asf_packet_len = AV_RL32(p + sizeof(ff_asf_guid) * 2 + 64); if (mms->asf_packet_len <= 0 || mms->asf_packet_len > sizeof(mms->in_buffer)) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (too large pkt_len %d)\n", mms->asf_packet_len); return AVERROR_INVALIDDATA; } } } else if (!memcmp(p, ff_asf_stream_header, sizeof(ff_asf_guid))) { flags = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24); stream_id = flags & 0x7F; //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size, //we can calcuate the packet size by stream_num. //Please see function send_stream_selection_request(). if (mms->stream_num < MAX_STREAMS && 46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) { mms->streams[mms->stream_num].id = stream_id; mms->stream_num++; } else { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (too many A/V streams)\n"); return AVERROR_INVALIDDATA; } } else if (!memcmp(p, ff_asf_head1_guid, sizeof(ff_asf_guid))) { chunksize = 46; // see references [2] section 3.4. This should be set 46. } p += chunksize; } return 0; }
static uint64_t inline get_k2(const uint8_t *src) { uint64_t k = AV_RL64(src + 8); k *= c2; k = ROT(k, 33); k *= c1; return k; }
static uint64_t inline get_k1(const uint8_t *src) { uint64_t k = AV_RL64(src); k *= c1; k = ROT(k, 31); k *= c2; return k; }
/* param change side data*/ static void dump_paramchange(void *ctx, AVPacketSideData *sd) { int size = sd->size; const uint8_t *data = sd->data; uint32_t flags, channels, sample_rate, width, height; uint64_t layout; if (!data || sd->size < 4) goto fail; flags = AV_RL32(data); data += 4; size -= 4; if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) { if (size < 4) goto fail; channels = AV_RL32(data); data += 4; size -= 4; av_log(ctx, AV_LOG_INFO, "channel count %d, ", channels); } if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) { if (size < 8) goto fail; layout = AV_RL64(data); data += 8; size -= 8; av_log(ctx, AV_LOG_INFO, "channel layout: %s, ", av_get_channel_name(layout)); } if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) { if (size < 4) goto fail; sample_rate = AV_RL32(data); data += 4; size -= 4; av_log(ctx, AV_LOG_INFO, "sample_rate %d, ", sample_rate); } if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) { if (size < 8) goto fail; width = AV_RL32(data); data += 4; size -= 4; height = AV_RL32(data); data += 4; size -= 4; av_log(ctx, AV_LOG_INFO, "width %d height %d", width, height); } return; fail: av_log(ctx, AV_LOG_INFO, "unknown param"); }
static double get_f64l(uint8_t *p) { return av_int2double(AV_RL64(p)); }
static int nist_probe(AVProbeData *p) { if (AV_RL64(p->buf) == AV_RL64("NIST_1A\x0a")) return AVPROBE_SCORE_MAX; return 0; }
static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret; unsigned int size; uint8_t *startmarker_ptr, *end, *search_end, marker; MXGContext *mxg = s->priv_data; while (!url_feof(s->pb) && !s->pb->error){ if (mxg->cache_size <= OVERREAD_SIZE) { /* update internal buffer */ ret = mxg_update_cache(s, DEFAULT_PACKET_SIZE + OVERREAD_SIZE); if (ret < 0) return ret; } end = mxg->buffer_ptr + mxg->cache_size; /* find start marker - 0xff */ if (mxg->cache_size > OVERREAD_SIZE) { search_end = end - OVERREAD_SIZE; startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end); } else { search_end = end; startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end); if (startmarker_ptr >= search_end - 1 || *(startmarker_ptr + 1) != EOI) break; } if (startmarker_ptr != search_end) { /* start marker found */ marker = *(startmarker_ptr + 1); mxg->buffer_ptr = startmarker_ptr + 2; mxg->cache_size = end - mxg->buffer_ptr; if (marker == SOI) { mxg->soi_ptr = startmarker_ptr; } else if (marker == EOI) { if (!mxg->soi_ptr) { av_log(s, AV_LOG_WARNING, "Found EOI before SOI, skipping\n"); continue; } pkt->pts = pkt->dts = mxg->dts; pkt->stream_index = 0; pkt->destruct = NULL; pkt->size = mxg->buffer_ptr - mxg->soi_ptr; pkt->data = mxg->soi_ptr; if (mxg->soi_ptr - mxg->buffer > mxg->cache_size) { if (mxg->cache_size > 0) { memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size); } mxg->buffer_ptr = mxg->buffer; } mxg->soi_ptr = 0; return pkt->size; } else if ( (SOF0 <= marker && marker <= SOF15) || (SOS <= marker && marker <= COM) ) { /* all other markers that start marker segment also contain length value (see specification for JPEG Annex B.1) */ size = AV_RB16(mxg->buffer_ptr); if (size < 2) return AVERROR(EINVAL); if (mxg->cache_size < size) { ret = mxg_update_cache(s, size); if (ret < 0) return ret; startmarker_ptr = mxg->buffer_ptr - 2; mxg->cache_size = 0; } else { mxg->cache_size -= size; } mxg->buffer_ptr += size; if (marker == APP13 && size >= 16) { /* audio data */ /* time (GMT) of first sample in usec since 1970, little-endian */ pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8); pkt->stream_index = 1; pkt->destruct = NULL; pkt->size = size - 14; pkt->data = startmarker_ptr + 16; if (startmarker_ptr - mxg->buffer > mxg->cache_size) { if (mxg->cache_size > 0) { memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size); } mxg->buffer_ptr = mxg->buffer; } return pkt->size; } else if (marker == COM && size >= 18 && !strncmp(startmarker_ptr + 4, "MXF", 3)) { /* time (GMT) of video frame in usec since 1970, little-endian */ mxg->dts = AV_RL64(startmarker_ptr + 12); } } } else { /* start marker not found */ mxg->buffer_ptr = search_end; mxg->cache_size = OVERREAD_SIZE; } } return AVERROR_EOF; }
int ff_mms_asf_header_parser(MMSContext *mms) { uint8_t *p = mms->asf_header; uint8_t *end; int flags, stream_id; mms->stream_num = 0; if (mms->asf_header_size < sizeof(ff_asf_guid) * 2 + 22 || memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (invalid ASF header, size=%d)\n", mms->asf_header_size); return AVERROR_INVALIDDATA; } end = mms->asf_header + mms->asf_header_size; p += sizeof(ff_asf_guid) + 14; while(end - p >= sizeof(ff_asf_guid) + 8) { uint64_t chunksize; if (!memcmp(p, ff_asf_data_header, sizeof(ff_asf_guid))) { chunksize = 50; // see Reference [2] section 5.1 } else { chunksize = AV_RL64(p + sizeof(ff_asf_guid)); } if (!chunksize || chunksize > end - p) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (header chunksize %"PRId64" is invalid)\n", chunksize); return AVERROR_INVALIDDATA; } if (!memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) { /* read packet size */ if (end - p > sizeof(ff_asf_guid) * 2 + 68) { mms->asf_packet_len = AV_RL32(p + sizeof(ff_asf_guid) * 2 + 64); mms->file_size = AV_RL64(p + sizeof(ff_asf_guid) * 2 + 8); mms->flags =AV_RL32(p+sizeof(ff_asf_guid)*2+56); if (mms->asf_packet_len <= 0 || mms->asf_packet_len > sizeof(mms->in_buffer)) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (too large pkt_len %d)\n", mms->asf_packet_len); return AVERROR_INVALIDDATA; } } } else if (!memcmp(p, ff_asf_stream_header, sizeof(ff_asf_guid))) { flags = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24); stream_id = flags & 0x7F; //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size, //we can calcuate the packet size by stream_num. //Please see function send_stream_selection_request(). if (mms->stream_num < MMS_MAX_STREAMS && 46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) { mms->streams = av_fast_realloc(mms->streams, &mms->nb_streams_allocated, (mms->stream_num + 1) * sizeof(MMSStream)); mms->streams[mms->stream_num].id = stream_id; mms->stream_num++; } else { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (too many A/V streams)\n"); return AVERROR_INVALIDDATA; } } else if (!memcmp(p, ff_asf_ext_stream_header, sizeof(ff_asf_guid))) { if (end - p >= 88) { int stream_count = AV_RL16(p + 84), ext_len_count = AV_RL16(p + 86); uint64_t skip_bytes = 88; while (stream_count--) { if (end - p < skip_bytes + 4) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (next stream name length is not in the buffer)\n"); return AVERROR_INVALIDDATA; } skip_bytes += 4 + AV_RL16(p + skip_bytes + 2); } while (ext_len_count--) { if (end - p < skip_bytes + 22) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (next extension system info length is not in the buffer)\n"); return AVERROR_INVALIDDATA; } skip_bytes += 22 + AV_RL32(p + skip_bytes + 18); } if (end - p < skip_bytes) { av_log(NULL, AV_LOG_ERROR, "Corrupt stream (the last extension system info length is invalid)\n"); return AVERROR_INVALIDDATA; } if (chunksize - skip_bytes > 24) chunksize = skip_bytes; } } else if (!memcmp(p, ff_asf_head1_guid, sizeof(ff_asf_guid))) { chunksize = 46; // see references [2] section 3.4. This should be set 46. } p += chunksize; } return 0; }
static int skeleton_header(AVFormatContext *s, int idx) { struct ogg *ogg = s->priv_data; struct ogg_stream *os = ogg->streams + idx; AVStream *st = s->streams[idx]; uint8_t *buf = os->buf + os->pstart; int version_major, version_minor; int64_t start_num, start_den; uint64_t start_granule; int target_idx, start_time; strcpy(st->codec->codec_name, "skeleton"); st->codec->codec_type = AVMEDIA_TYPE_DATA; if (os->psize < 8) return -1; if (!strncmp(buf, "fishead", 8)) { if (os->psize < 64) return -1; version_major = AV_RL16(buf+8); version_minor = AV_RL16(buf+10); if (version_major != 3) { av_log(s, AV_LOG_WARNING, "Unknown skeleton version %d.%d\n", version_major, version_minor); return -1; } // This is the overall start time. We use it for the start time of // of the skeleton stream since if left unset lavf assumes 0, // which we don't want since skeleton is timeless // FIXME: the real meaning of this field is "start playback at // this time which can be in the middle of a packet start_num = AV_RL64(buf+12); start_den = AV_RL64(buf+20); if (start_den) { int base_den; av_reduce(&start_time, &base_den, start_num, start_den, INT_MAX); avpriv_set_pts_info(st, 64, 1, base_den); os->lastpts = st->start_time = start_time; } } else if (!strncmp(buf, "fisbone", 8)) { if (os->psize < 52) return -1; target_idx = ogg_find_stream(ogg, AV_RL32(buf+12)); start_granule = AV_RL64(buf+36); if (os->start_granule != OGG_NOGRANULE_VALUE) { av_log_missing_feature(s, "multiple fisbone for the same stream", 0); return 1; } if (target_idx >= 0 && start_granule != OGG_NOGRANULE_VALUE) { os->start_granule = start_granule; } } return 1; }
static int get_ext_stream_properties(char *buf, int buf_len, int stream_num, struct asf_priv* asf, int is_video) { int pos=0; uint8_t *buffer = &buf[0]; uint64_t avg_ft; unsigned bitrate; while ((pos = find_asf_guid(buf, asf_ext_stream_header, pos, buf_len)) >= 0) { int this_stream_num, stnamect, payct, i; int buf_max_index=pos+50; if (buf_max_index > buf_len) return 0; buffer = &buf[pos]; // the following info is available // some of it may be useful but we're skipping it for now // starttime(8 bytes), endtime(8), // leak-datarate(4), bucket-datasize(4), init-bucket-fullness(4), // alt-leak-datarate(4), alt-bucket-datasize(4), alt-init-bucket-fullness(4), // max-object-size(4), // flags(4) (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved) buffer += 8+8; bitrate = AV_RL32(buffer); buffer += 8*4; this_stream_num=AV_RL16(buffer);buffer+=2; if (this_stream_num == stream_num) { buf_max_index+=14; if (buf_max_index > buf_len) return 0; buffer+=2; //skip stream-language-id-index avg_ft = AV_RL64(buffer); // provided in 100ns units buffer+=8; asf->bps = bitrate / 8; // after this are values for stream-name-count and // payload-extension-system-count // followed by associated info for each stnamect = AV_RL16(buffer);buffer+=2; payct = AV_RL16(buffer);buffer+=2; // need to read stream names if present in order // to get lengths - values are ignored for now for (i=0; i<stnamect; i++) { int stream_name_len; buf_max_index+=4; if (buf_max_index > buf_len) return 0; buffer+=2; //language_id_index stream_name_len = AV_RL16(buffer);buffer+=2; buffer+=stream_name_len; //stream_name buf_max_index+=stream_name_len; if (buf_max_index > buf_len) return 0; } if (is_video) { asf->vid_repdata_count = payct; asf->vid_repdata_sizes = malloc(payct*sizeof(int)); } else { asf->aud_repdata_count = payct; asf->aud_repdata_sizes = malloc(payct*sizeof(int)); } for (i=0; i<payct; i++) { int payload_len; buf_max_index+=22; if (buf_max_index > buf_len) return 0; // Each payload extension definition starts with a GUID. // In dvr-ms files one of these indicates the presence an // extension that contains pts values and this is always present // in the video and audio streams. // Another GUID indicates the presence of an extension // that contains useful video frame demuxing information. // Note that the extension data in each packet does not contain // these GUIDs and that this header section defines the order the data // will appear in. if (memcmp(buffer, asf_dvr_ms_timing_rep_data, 16) == 0) { if (is_video) asf->vid_ext_timing_index = i; else asf->aud_ext_timing_index = i; } else if (is_video && memcmp(buffer, asf_dvr_ms_vid_frame_rep_data, 16) == 0) asf->vid_ext_frame_index = i; buffer+=16; payload_len = AV_RL16(buffer);buffer+=2; if (is_video) asf->vid_repdata_sizes[i] = payload_len; else asf->aud_repdata_sizes[i] = payload_len; buffer+=4;//sys_len } return 1; } } return 1; }
static int dsf_probe(AVProbeData *p) { if (p->buf_size < 12 || memcmp(p->buf, "DSD ", 4) || AV_RL64(p->buf + 4) != 28) return 0; return AVPROBE_SCORE_MAX; }
static int asf_streaming_parse_header(int fd, streaming_ctrl_t* streaming_ctrl) { ASF_stream_chunck_t chunk; asf_http_streaming_ctrl_t* asf_ctrl = streaming_ctrl->data; char* buffer=NULL, *chunk_buffer=NULL; int i,r,size,pos = 0; int start; int buffer_size = 0; int chunk_size2read = 0; int bw = streaming_ctrl->bandwidth; int *v_rates = NULL, *a_rates = NULL; int v_rate = 0, a_rate = 0, a_idx = -1, v_idx = -1; if(asf_ctrl == NULL) return -1; // The ASF header can be in several network chunks. For example if the content description // is big, the ASF header will be split in 2 network chunk. // So we need to retrieve all the chunk before starting to parse the header. do { if (asf_read_wrapper(fd, &chunk, sizeof(ASF_stream_chunck_t), streaming_ctrl) <= 0) return -1; // Endian handling of the stream chunk le2me_ASF_stream_chunck_t(&chunk); size = asf_streaming( &chunk, &r) - sizeof(ASF_stream_chunck_t); if(r) mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_ASF_WarnDropHeader); if(size < 0){ mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); return -1; } if (chunk.type != ASF_STREAMING_HEADER) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoHeaderAtFirstChunk); return -1; } // audit: do not overflow buffer_size if (size > SIZE_MAX - buffer_size) return -1; buffer = malloc(size+buffer_size); if(buffer == NULL) { mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_ASF_BufferMallocFailed,size+buffer_size); return -1; } if( chunk_buffer!=NULL ) { memcpy( buffer, chunk_buffer, buffer_size ); free( chunk_buffer ); } chunk_buffer = buffer; buffer += buffer_size; buffer_size += size; if (asf_read_wrapper(fd, buffer, size, streaming_ctrl) <= 0) return -1; if( chunk_size2read==0 ) { ASF_header_t *asfh = (ASF_header_t *)buffer; if(size < (int)sizeof(ASF_header_t)) { mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunk2Small); return -1; } else mp_msg(MSGT_NETWORK,MSGL_DBG2,"Got chunk\n"); chunk_size2read = AV_RL64(&asfh->objh.size); mp_msg(MSGT_NETWORK,MSGL_DBG2,"Size 2 read=%d\n", chunk_size2read); } } while( buffer_size<chunk_size2read); buffer = chunk_buffer; size = buffer_size; start = sizeof(ASF_header_t); pos = find_asf_guid(buffer, asf_file_header_guid, start, size); if (pos >= 0) { ASF_file_header_t *fileh = (ASF_file_header_t *) &buffer[pos]; pos += sizeof(ASF_file_header_t); if (pos > size) goto len_err_out; /* if(fileh.packetsize != fileh.packetsize2) { printf("Error packetsize check don't match\n"); return -1; } */ asf_ctrl->packet_size = AV_RL32(&fileh->max_packet_size); // before playing. // preroll: time in ms to bufferize before playing streaming_ctrl->prebuffer_size = (unsigned int)(((double)fileh->preroll/1000.0)*((double)fileh->max_bitrate/8.0)); } pos = start; while ((pos = find_asf_guid(buffer, asf_stream_header_guid, pos, size)) >= 0) { ASF_stream_header_t *streamh = (ASF_stream_header_t *)&buffer[pos]; pos += sizeof(ASF_stream_header_t); if (pos > size) goto len_err_out; switch(ASF_LOAD_GUID_PREFIX(streamh->type)) { case 0xF8699E40 : // audio stream if(asf_ctrl->audio_streams == NULL){ asf_ctrl->audio_streams = malloc(sizeof(int)); asf_ctrl->n_audio = 1; } else { asf_ctrl->n_audio++; asf_ctrl->audio_streams = realloc(asf_ctrl->audio_streams, asf_ctrl->n_audio*sizeof(int)); } asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = AV_RL16(&streamh->stream_no); break; case 0xBC19EFC0 : // video stream if(asf_ctrl->video_streams == NULL){ asf_ctrl->video_streams = malloc(sizeof(int)); asf_ctrl->n_video = 1; } else { asf_ctrl->n_video++; asf_ctrl->video_streams = realloc(asf_ctrl->video_streams, asf_ctrl->n_video*sizeof(int)); } asf_ctrl->video_streams[asf_ctrl->n_video-1] = AV_RL16(&streamh->stream_no); break; } } // always allocate to avoid lots of ifs later v_rates = calloc(asf_ctrl->n_video, sizeof(int)); a_rates = calloc(asf_ctrl->n_audio, sizeof(int)); pos = find_asf_guid(buffer, asf_stream_group_guid, start, size); if (pos >= 0) { // stream bitrate properties object int stream_count; char *ptr = &buffer[pos]; char *end = &buffer[size]; mp_msg(MSGT_NETWORK, MSGL_V, "Stream bitrate properties object\n"); if (ptr + 2 > end) goto len_err_out; stream_count = AV_RL16(ptr); ptr += 2; mp_msg(MSGT_NETWORK, MSGL_V, " stream count=[0x%x][%u]\n", stream_count, stream_count ); for( i=0 ; i<stream_count ; i++ ) { uint32_t rate; int id; int j; if (ptr + 6 > end) goto len_err_out; id = AV_RL16(ptr); ptr += 2; rate = AV_RL32(ptr); ptr += 4; mp_msg(MSGT_NETWORK, MSGL_V, " stream id=[0x%x][%u]\n", id, id); mp_msg(MSGT_NETWORK, MSGL_V, " max bitrate=[0x%x][%u]\n", rate, rate); for (j = 0; j < asf_ctrl->n_video; j++) { if (id == asf_ctrl->video_streams[j]) { mp_msg(MSGT_NETWORK, MSGL_V, " is video stream\n"); v_rates[j] = rate; break; } } for (j = 0; j < asf_ctrl->n_audio; j++) { if (id == asf_ctrl->audio_streams[j]) { mp_msg(MSGT_NETWORK, MSGL_V, " is audio stream\n"); a_rates[j] = rate; break; } } } } free(buffer); // automatic stream selection based on bandwidth if (bw == 0) bw = INT_MAX; mp_msg(MSGT_NETWORK, MSGL_V, "Max bandwidth set to %d\n", bw); if (asf_ctrl->n_audio) { // find lowest-bitrate audio stream a_rate = a_rates[0]; a_idx = 0; for (i = 0; i < asf_ctrl->n_audio; i++) { if (a_rates[i] < a_rate) { a_rate = a_rates[i]; a_idx = i; } } if (max_idx(asf_ctrl->n_video, v_rates, bw - a_rate) < 0) { // both audio and video are not possible, try video only next a_idx = -1; a_rate = 0; } } // find best video stream v_idx = max_idx(asf_ctrl->n_video, v_rates, bw - a_rate); if (v_idx >= 0) v_rate = v_rates[v_idx]; // find best audio stream a_idx = max_idx(asf_ctrl->n_audio, a_rates, bw - v_rate); free(v_rates); free(a_rates); if (a_idx < 0 && v_idx < 0) { mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_Bandwidth2SmallCannotPlay); return -1; } if (audio_id > 0) // a audio stream was forced asf_ctrl->audio_id = audio_id; else if (a_idx >= 0) asf_ctrl->audio_id = asf_ctrl->audio_streams[a_idx]; else if (asf_ctrl->n_audio) { mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedAudio); audio_id = -2; } if (video_id > 0) // a video stream was forced asf_ctrl->video_id = video_id; else if (v_idx >= 0) asf_ctrl->video_id = asf_ctrl->video_streams[v_idx]; else if (asf_ctrl->n_video) { mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedVideo); video_id = -2; } return 1; len_err_out: mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_InvalidLenInHeader); free(buffer); free(v_rates); free(a_rates); return -1; }