AVIOContext *avio_alloc_context( unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence)) { AVIOContext *s = av_mallocz(sizeof(AVIOContext)); if (!s) return NULL; ffio_init_context(s, buffer, buffer_size, write_flag, opaque, read_packet, write_packet, seek); return s; }
/**< return 0 on packet, no more left, 1 on packet, 1 on partial packet... */ static int rdt_parse_packet (AVFormatContext *ctx, PayloadContext *rdt, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, int flags) { int seq = 1, res; AVIOContext pb; if (rdt->audio_pkt_cnt == 0) { int pos; ffio_init_context(&pb, (unsigned char*)buf, len, 0, NULL, NULL, NULL, NULL); flags = (flags & RTP_FLAG_KEY) ? 2 : 0; res = ff_rm_parse_packet (rdt->rmctx, &pb, st, rdt->rmst[st->index], len, pkt, &seq, flags, *timestamp); pos = avio_tell(&pb); if (res < 0) return res; if (res > 0) { if (st->codec->codec_id == CODEC_ID_AAC) { memcpy (rdt->buffer, buf + pos, len - pos); rdt->rmctx->pb = avio_alloc_context ((unsigned char *)rdt->buffer, len - pos, 0, NULL, NULL, NULL, NULL); } goto get_cache; } } else { get_cache: rdt->audio_pkt_cnt = ff_rm_retrieve_cache (rdt->rmctx, rdt->rmctx->pb, st, rdt->rmst[st->index], pkt); if (rdt->audio_pkt_cnt == 0 && st->codec->codec_id == CODEC_ID_AAC) av_freep(&rdt->rmctx->pb); } pkt->stream_index = st->index; pkt->pts = *timestamp; return rdt->audio_pkt_cnt > 0; }
static int asf_write_header(AVFormatContext *s) { ASFContext *asf = s->priv_data; s->packet_size = asf->packet_size; s->max_interleave_delta = 0; asf->nb_packets = 0; if (s->nb_streams > 127) { av_log(s, AV_LOG_ERROR, "ASF can only handle 127 streams\n"); return AVERROR(EINVAL); } asf->index_ptr = av_malloc(sizeof(ASFIndex) * ASF_INDEX_BLOCK); if (!asf->index_ptr) return AVERROR(ENOMEM); asf->nb_index_memory_alloc = ASF_INDEX_BLOCK; asf->maximum_packet = 0; /* the data-chunk-size has to be 50 (DATA_HEADER_SIZE), which is * data_size - asf->data_offset at the moment this function is done. * It is needed to use asf as a streamable format. */ if (asf_write_header1(s, 0, DATA_HEADER_SIZE) < 0) { //av_free(asf); av_freep(&asf->index_ptr); return -1; } avio_flush(s->pb); asf->packet_nb_payloads = 0; asf->packet_timestamp_start = -1; asf->packet_timestamp_end = -1; ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1, NULL, NULL, NULL, NULL); if (s->avoid_negative_ts < 0) s->avoid_negative_ts = 1; return 0; }
static int cmf_read_header(AVFormatContext *s, AVFormatParameters *ap) { struct cmf *bs = s->priv_data; memset(bs, 0, sizeof(*bs)); ap=ap; AVIOContext *pb=s->pb; if (pb->read_packet || pb->seek) { ffio_fdopen_resetlpbuf(pb,0); ffio_init_context(pb, pb->buffer, pb->buffer_size, 0, pb->opaque, NULL, NULL, NULL);/*reset old pb*/ pb->is_slowmedia=0; pb->is_streamed=1; pb->seekable=0; pb->support_time_seek = 0; } int temp = 0; int ret = cmf_parser_next_slice(s, &temp, 1); bs->parsering_index = temp; return ret; }
static int hls_read_header(AVFormatContext *s) { HLSContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; c->interrupt_callback = &s->interrupt_callback; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If the playlist only contained variants, parse each individual * variant playlist. */ if (c->n_variants > 1 || c->variants[0]->n_segments == 0) { for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) goto fail; } } if (c->variants[0]->n_segments == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If this isn't a live stream, calculate the total duration of the * stream. */ if (c->variants[0]->finished) { int64_t duration = 0; for (i = 0; i < c->variants[0]->n_segments; i++) duration += c->variants[0]->segments[i]->duration; s->duration = duration * AV_TIME_BASE; } /* Open the demuxer for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; AVProgram * program = NULL; if (v->n_segments == 0) continue; if (!(v->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; } v->index = i; v->needed = 1; v->parent = s; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ v->cur_seq_no = v->start_seq_no; if (!v->finished && v->n_segments > 3) v->cur_seq_no = v->start_seq_no + v->n_segments - 3; v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v, read_data, NULL, NULL); v->pb.seekable = 0; ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url, NULL, 0, 0); if (ret < 0) { /* Free the ctx - it isn't initialized properly at this point, * so avformat_close_input shouldn't be called. If * avformat_open_input fails below, it frees and zeros the * context, so it doesn't need any special treatment like this. */ av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url); avformat_free_context(v->ctx); v->ctx = NULL; goto fail; } v->ctx->pb = &v->pb; ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; v->stream_offset = stream_offset; v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; ret = avformat_find_stream_info(v->ctx, NULL); if (ret < 0) goto fail; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); /* Create new AVprogram for variant i */ program = av_new_program(s, i); if ( !program ) goto fail; av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0); program->bitrate = v->bandwidth; /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { AVStream *st = avformat_new_stream(s, NULL); if (!st) { ret = AVERROR(ENOMEM); goto fail; } ff_program_add_stream_index(s, i, st->index); st->id = i; avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); if (v->bandwidth) av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, 0); } stream_offset += v->ctx->nb_streams; } c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; c->seek_timestamp = AV_NOPTS_VALUE; return 0; fail: free_variant_list(c); return ret; }
static int sap_read_header(AVFormatContext *s) { struct SAPState *sap = s->priv_data; char host[1024], path[1024], url[1024]; uint8_t recvbuf[RTP_MAX_PACKET_LENGTH]; int port; int ret, i; AVInputFormat* infmt; if (!ff_network_init()) return AVERROR(EIO); av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), s->filename); if (port < 0) port = 9875; if (!host[0]) { /* Listen for announcements on sap.mcast.net if no host was specified */ av_strlcpy(host, "224.2.127.254", sizeof(host)); } ff_url_join(url, sizeof(url), "udp", NULL, host, port, "?localport=%d", port); ret = ffurl_open(&sap->ann_fd, url, AVIO_FLAG_READ, &s->interrupt_callback, NULL); if (ret) goto fail; while (1) { int addr_type, auth_len; int pos; ret = ffurl_read(sap->ann_fd, recvbuf, sizeof(recvbuf) - 1); if (ret == AVERROR(EAGAIN)) continue; if (ret < 0) goto fail; recvbuf[ret] = '\0'; /* Null terminate for easier parsing */ if (ret < 8) { av_log(s, AV_LOG_WARNING, "Received too short packet\n"); continue; } if ((recvbuf[0] & 0xe0) != 0x20) { av_log(s, AV_LOG_WARNING, "Unsupported SAP version packet " "received\n"); continue; } if (recvbuf[0] & 0x04) { av_log(s, AV_LOG_WARNING, "Received stream deletion " "announcement\n"); continue; } addr_type = recvbuf[0] & 0x10; auth_len = recvbuf[1]; sap->hash = AV_RB16(&recvbuf[2]); pos = 4; if (addr_type) pos += 16; /* IPv6 */ else pos += 4; /* IPv4 */ pos += auth_len * 4; if (pos + 4 >= ret) { av_log(s, AV_LOG_WARNING, "Received too short packet\n"); continue; } #define MIME "application/sdp" if (strcmp(&recvbuf[pos], MIME) == 0) { pos += strlen(MIME) + 1; } else if (strncmp(&recvbuf[pos], "v=0\r\n", 5) == 0) { // Direct SDP without a mime type } else { av_log(s, AV_LOG_WARNING, "Unsupported mime type %s\n", &recvbuf[pos]); continue; } sap->sdp = av_strdup(&recvbuf[pos]); break; } av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sap->sdp); ffio_init_context(&sap->sdp_pb, sap->sdp, strlen(sap->sdp), 0, NULL, NULL, NULL, NULL); infmt = av_find_input_format("sdp"); if (!infmt) goto fail; sap->sdp_ctx = avformat_alloc_context(); if (!sap->sdp_ctx) { ret = AVERROR(ENOMEM); goto fail; } sap->sdp_ctx->max_delay = s->max_delay; sap->sdp_ctx->pb = &sap->sdp_pb; sap->sdp_ctx->interrupt_callback = s->interrupt_callback; ret = avformat_open_input(&sap->sdp_ctx, "temp.sdp", infmt, NULL); if (ret < 0) goto fail; if (sap->sdp_ctx->ctx_flags & AVFMTCTX_NOHEADER) s->ctx_flags |= AVFMTCTX_NOHEADER; for (i = 0; i < sap->sdp_ctx->nb_streams; i++) { AVStream *st = avformat_new_stream(s, NULL); if (!st) { ret = AVERROR(ENOMEM); goto fail; } st->id = i; avcodec_copy_context(st->codec, sap->sdp_ctx->streams[i]->codec); st->time_base = sap->sdp_ctx->streams[i]->time_base; } return 0; fail: sap_read_close(s); return ret; }
/** * @return 0 when a packet was written into /p pkt, and no more data is left; * 1 when a packet was written into /p pkt, and more packets might be left; * <0 when not enough data was provided to return a full packet, or on error. */ static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags) { AVIOContext *pb = &asf->pb; int res, mflags, len_off; RTSPState *rt = s->priv_data; if (!rt->asf_ctx) return -1; if (len > 0) { int off, out_len = 0; if (len < 4) return -1; av_freep(&asf->buf); ffio_init_context(pb, buf, len, 0, NULL, NULL, NULL, NULL); while (avio_tell(pb) + 4 < len) { int start_off = avio_tell(pb); mflags = avio_r8(pb); if (mflags & 0x80) flags |= RTP_FLAG_KEY; len_off = avio_rb24(pb); if (mflags & 0x20) /**< relative timestamp */ avio_skip(pb, 4); if (mflags & 0x10) /**< has duration */ avio_skip(pb, 4); if (mflags & 0x8) /**< has location ID */ avio_skip(pb, 4); off = avio_tell(pb); if (!(mflags & 0x40)) { /** * If 0x40 is not set, the len_off field specifies an offset * of this packet's payload data in the complete (reassembled) * ASF packet. This is used to spread one ASF packet over * multiple RTP packets. */ if (asf->pktbuf && len_off != avio_tell(asf->pktbuf)) { uint8_t *p; avio_close_dyn_buf(asf->pktbuf, &p); asf->pktbuf = NULL; av_free(p); } if (!len_off && !asf->pktbuf && (res = avio_open_dyn_buf(&asf->pktbuf)) < 0) return res; if (!asf->pktbuf) return AVERROR(EIO); avio_write(asf->pktbuf, buf + off, len - off); avio_skip(pb, len - off); if (!(flags & RTP_FLAG_MARKER)) return -1; out_len = avio_close_dyn_buf(asf->pktbuf, &asf->buf); asf->pktbuf = NULL; } else { /** * If 0x40 is set, the len_off field specifies the length of * the next ASF packet that can be read from this payload * data alone. This is commonly the same as the payload size, * but could be less in case of packet splitting (i.e. * multiple ASF packets in one RTP packet). */ int cur_len = start_off + len_off - off; int prev_len = out_len; out_len += cur_len; if (FFMIN(cur_len, len - off) < 0) return -1; if ((res = av_reallocp(&asf->buf, out_len)) < 0) return res; memcpy(asf->buf + prev_len, buf + off, FFMIN(cur_len, len - off)); avio_skip(pb, cur_len); } } init_packetizer(pb, asf->buf, out_len); pb->pos += rt->asf_pb_pos; pb->eof_reached = 0; rt->asf_ctx->pb = pb; } for (;;) { int i; res = ff_read_packet(rt->asf_ctx, pkt); rt->asf_pb_pos = avio_tell(pb); if (res != 0) break; for (i = 0; i < s->nb_streams; i++) { if (s->streams[i]->id == rt->asf_ctx->streams[pkt->stream_index]->id) { pkt->stream_index = i; return 1; // FIXME: return 0 if last packet } } av_free_packet(pkt); } return res == 1 ? -1 : res; }
static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) { AppleHTTPContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If the playlist only contained variants, parse each individual * variant playlist. */ if (c->n_variants > 1 || c->variants[0]->n_segments == 0) { for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) goto fail; } } if (c->variants[0]->n_segments == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If this isn't a live stream, calculate the total duration of the * stream. */ if (c->variants[0]->finished) { int64_t duration = 0; for (i = 0; i < c->variants[0]->n_segments; i++) duration += c->variants[0]->segments[i]->duration; s->duration = duration * AV_TIME_BASE; } /* Open the demuxer for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; if (v->n_segments == 0) continue; v->index = i; v->needed = 1; v->parent = s; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ v->cur_seq_no = v->start_seq_no; if (!v->finished && v->n_segments > 3) v->cur_seq_no = v->start_seq_no + v->n_segments - 3; v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v, read_data, NULL, NULL); v->pb.seekable = 0; ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url, NULL, 0, 0); if (ret < 0) goto fail; ret = av_open_input_stream(&v->ctx, &v->pb, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; v->stream_offset = stream_offset; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { AVStream *st = av_new_stream(s, i); if (!st) { ret = AVERROR(ENOMEM); goto fail; } avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); av_metadata_set2(&st->metadata, "variant_bitrate", bitrate_str, 0); } stream_offset += v->ctx->nb_streams; } c->first_packet = 1; return 0; fail: free_variant_list(c); return ret; }
static int hls_read_header(AVFormatContext *s) { HLSContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; int only_parser_one_variants=1; int parser_start,parser_end; //c->interrupt_callback = &s->interrupt_callback; c->total_brate=500*1024; c->latest_3file_brate=c->total_brate; c->latest_1file_brate=c->total_brate; s->bit_rate=0; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0){ av_log(NULL, AV_LOG_WARNING, "parse_playlist failed ret=%d\n",ret); goto fail; } if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist 1\n"); ret = AVERROR_EOF; goto fail; } /* If the playlist only contained variants, parse each individual * variant playlist. */ if (c->n_variants > 1 || c->variants[0]->n_segments == 0) { for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) goto fail; } } if (c->variants[0]->n_segments == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist 2\n"); ret = AVERROR_EOF; goto fail; } /* If this isn't a live stream, calculate the total duration of the * stream. */ if (c->variants[0]->finished) { int64_t duration = 0; for (i = 0; i < c->variants[0]->n_segments; i++) duration += c->variants[0]->segments[i]->duration; s->duration = duration * AV_TIME_BASE; } if(only_parser_one_variants){ parser_start=select_best_variant(c,c->total_brate); parser_end=parser_start+1; }else{ parser_start=0; parser_end=c->n_variants; } /* Open the demuxer for each variant */ for (i = parser_start; i < parser_end; i++) { struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; if (v->n_segments == 0) continue; if (!(v->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; } v->index = i; v->needed = 1; v->parent = s; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ v->cur_seq_no = v->start_seq_no; if (!v->finished && v->n_segments > 3) v->cur_seq_no = v->start_seq_no + v->n_segments - 3; #ifdef USED_LP_BUF v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); memset(&v->urllpbuf,0,sizeof(&v->urllpbuf)); if(url_lpopen_ex(&v->urllpbuf,0,AVIO_FLAG_READ,read_data,read_data_exseek)==0){ ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, &v->urllpbuf, url_lpread, NULL, NULL); }else{ ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, &v->urllpbuf, read_data, NULL, NULL); } v->urllpbuf.is_streamed=1; v->urllpbuf.is_slowmedia=1; v->urllpbuf.priv_data=v; #else v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v, read_data, NULL, NULL); #endif v->pb.seekable = 0; ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url, NULL, 0, 0); if (ret < 0) { /* Free the ctx - it isn't initialized properly at this point, * so avformat_close_input shouldn't be called. If * avformat_open_input fails below, it frees and zeros the * context, so it doesn't need any special treatment like this. */ avformat_free_context(v->ctx); v->ctx = NULL; goto fail; } v->ctx->pb = &v->pb; ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; if(v->bandwidth<=0 && v->segments[0]->seg_filesize>0 && v->segments[0]->duration>0){ v->bandwidth=v->segments[0]->seg_filesize/v->segments[0]->duration; } v->stream_offset = stream_offset; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { AVStream *st = av_new_stream(s, 0); if (!st) { ret = AVERROR(ENOMEM); goto fail; } st->id = i; avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); if (v->bandwidth) av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, 0); if(st->codec->bit_rate<=0) st->codec->bit_rate=v->bandwidth/v->ctx->nb_streams; } v->ctx->bit_rate=v->bandwidth; stream_offset += v->ctx->nb_streams; s->bit_rate+=v->bandwidth; } c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; c->seek_timestamp = AV_NOPTS_VALUE; c->discontinue_pts_interval_ms=2000; s->flags|=AVFMT_FLAG_FILESIZE_NOT_VALID; if(s->pb){ /*reset read and free lp buf.*/ /*del lp buf,to free memory*/ ffio_fdopen_resetlpbuf(s->pb,0); s->pb->flags|=AVIO_FLAG_SIZE_NOTVALID; s->file_size=-1; } return 0; fail: free_variant_list(c); return ret; }
static int hls_read_header(AVFormatContext *s) { URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque; HLSContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; c->interrupt_callback = &s->interrupt_callback; // if the URL context is good, read important options we must broker later if (u && u->prot->priv_data_class) { // get the previous user agent & set back to null if string size is zero av_freep(&c->user_agent); av_opt_get(u->priv_data, "user-agent", 0, (uint8_t**)&(c->user_agent)); if (c->user_agent && !strlen(c->user_agent)) av_freep(&c->user_agent); // get the previous cookies & set back to null if string size is zero av_freep(&c->cookies); av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies)); if (c->cookies && !strlen(c->cookies)) av_freep(&c->cookies); // get the previous headers & set back to null if string size is zero av_freep(&c->headers); av_opt_get(u->priv_data, "headers", 0, (uint8_t**)&(c->headers)); if (c->headers && !strlen(c->headers)) av_freep(&c->headers); } if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If the playlist only contained playlists (Master Playlist), * parse each individual playlist. */ if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) { for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0) goto fail; } } if (c->variants[0]->playlists[0]->n_segments == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If this isn't a live stream, calculate the total duration of the * stream. */ if (c->variants[0]->playlists[0]->finished) { int64_t duration = 0; for (i = 0; i < c->variants[0]->playlists[0]->n_segments; i++) duration += c->variants[0]->playlists[0]->segments[i]->duration; s->duration = duration; } /* Open the demuxer for each playlist */ for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; AVInputFormat *in_fmt = NULL; if (pls->n_segments == 0) continue; if (!(pls->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; } pls->index = i; pls->needed = 1; pls->parent = s; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ pls->cur_seq_no = pls->start_seq_no; if (!pls->finished && pls->n_segments > 3) pls->cur_seq_no = pls->start_seq_no + pls->n_segments - 3; pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); ffio_init_context(&pls->pb, pls->read_buffer, INITIAL_BUFFER_SIZE, 0, pls, read_data, NULL, NULL); pls->pb.seekable = 0; ret = av_probe_input_buffer(&pls->pb, &in_fmt, pls->segments[0]->url, NULL, 0, 0); if (ret < 0) { /* Free the ctx - it isn't initialized properly at this point, * so avformat_close_input shouldn't be called. If * avformat_open_input fails below, it frees and zeros the * context, so it doesn't need any special treatment like this. */ av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", pls->segments[0]->url); avformat_free_context(pls->ctx); pls->ctx = NULL; goto fail; } pls->ctx->pb = &pls->pb; pls->stream_offset = stream_offset; ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; ret = avformat_find_stream_info(pls->ctx, NULL); if (ret < 0) goto fail; /* Create new AVStreams for each stream in this playlist */ for (j = 0; j < pls->ctx->nb_streams; j++) { AVStream *st = avformat_new_stream(s, NULL); AVStream *ist = pls->ctx->streams[j]; if (!st) { ret = AVERROR(ENOMEM); goto fail; } st->id = i; avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); avcodec_copy_context(st->codec, pls->ctx->streams[j]->codec); } stream_offset += pls->ctx->nb_streams; } /* Create a program for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; char bitrate_str[20]; AVProgram *program; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); program = av_new_program(s, i); if (!program) goto fail; av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0); for (j = 0; j < v->n_playlists; j++) { struct playlist *pls = v->playlists[j]; int is_shared = playlist_in_multiple_variants(c, pls); int k; for (k = 0; k < pls->ctx->nb_streams; k++) { struct AVStream *st = s->streams[pls->stream_offset + k]; ff_program_add_stream_index(s, i, pls->stream_offset + k); /* Set variant_bitrate for streams unique to this variant */ if (!is_shared && v->bandwidth) av_dict_set(&st->metadata, "variant_bitrate", bitrate_str, 0); } } } c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; c->seek_timestamp = AV_NOPTS_VALUE; return 0; fail: free_playlist_list(c); free_variant_list(c); return ret; }
void ff_text_init_buf(FFTextReader *r, void *buf, size_t size) { memset(&r->buf_pb, 0, sizeof(r->buf_pb)); ffio_init_context(&r->buf_pb, buf, size, 0, NULL, NULL, NULL, NULL); ff_text_init_avio(r, &r->buf_pb); }