static char* mpjpeg_get_boundary(AVIOContext* pb) { uint8_t *mime_type = NULL; const char *start; const char *end; uint8_t *res = NULL; int len; /* get MIME type, and skip to the first parameter */ av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type); start = mime_type; while (start != NULL && *start != '\0') { start = strchr(start, ';'); if (!start) break; start = start+1; while (av_isspace(*start)) start++; if (!av_stristart(start, "boundary=", &start)) { end = strchr(start, ';'); if (end) len = end - start - 1; else len = strlen(start); res = av_strndup(start, len); break; } } av_freep(&mime_type); return res; }
AVFormatContext *ff_rtp_chain_mux_open(AVFormatContext *s, AVStream *st, URLContext *handle, int packet_size) { AVFormatContext *rtpctx; int ret; AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); uint8_t *rtpflags; AVDictionary *opts = NULL; if (!rtp_format) return NULL; /* Allocate an AVFormatContext for each output stream */ rtpctx = avformat_alloc_context(); if (!rtpctx) return NULL; rtpctx->oformat = rtp_format; if (!av_new_stream(rtpctx, 0)) { av_free(rtpctx); return NULL; } /* Copy the max delay setting; the rtp muxer reads this. */ rtpctx->max_delay = s->max_delay; /* Copy other stream parameters. */ rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio; if (av_opt_get(s, "rtpflags", AV_OPT_SEARCH_CHILDREN, &rtpflags) >= 0) av_dict_set(&opts, "rtpflags", rtpflags, AV_DICT_DONT_STRDUP_VAL); /* Set the synchronized start time. */ rtpctx->start_time_realtime = s->start_time_realtime; avcodec_copy_context(rtpctx->streams[0]->codec, st->codec); if (handle) { ffio_fdopen(&rtpctx->pb, handle); } else ffio_open_dyn_packet_buf(&rtpctx->pb, packet_size); ret = avformat_write_header(rtpctx, &opts); av_dict_free(&opts); if (ret) { if (handle) { avio_close(rtpctx->pb); } else { uint8_t *ptr; avio_close_dyn_buf(rtpctx->pb, &ptr); av_free(ptr); } avformat_free_context(rtpctx); return NULL; } return rtpctx; }
void set_shoutcast_metadata(AVFormatContext *ic) { char *value = NULL; if (av_opt_get(ic, "icy_metadata_packet", 1, (uint8_t **) &value) < 0) { value = NULL; } if (value && value[0]) { av_dict_set(&ic->metadata, ICY_METADATA, value, 0); } }
std::string Option::getString() const { void* out_val = av_malloc( 128 ); int error = av_opt_get( _avContext, getName().c_str(), AV_OPT_SEARCH_CHILDREN, (uint8_t**)&out_val ); std::string strValue( out_val ? reinterpret_cast<const char*>( out_val ) : "" ); av_free( out_val ); checkFFmpegGetOption( error ); return strValue; }
char* Property :: getPropertyAsString(void *aContext, const char *aName) { char* retval = 0; char *value = 0; try { if (!aContext) throw std::runtime_error("no context passed in"); if (!aName || !*aName) throw std::runtime_error("empty property name passed to setProperty"); // we don't allow a string value longer than this. This is // actually safe because this buffer is only used for non-string options if (av_opt_get(aContext, aName, 0, (uint8_t**)&value) < 0) throw std::runtime_error("could not get property"); if (value) { // let's make a copy of the data int32_t valLen = strlen(value); if (valLen > 0) { retval = new char[valLen+1]; if (!retval) throw std::bad_alloc(); // copy the data strncpy(retval, value, valLen+1); } } } catch (std::exception & e) { VS_LOG_DEBUG("Error: %s", e.what()); if (retval) delete [] retval; retval = 0; } if (value) av_free(value); // NOTE: Caller must call delete[] on returned value; we mean it! return retval; }
static int save_avio_options(AVFormatContext *s) { HLSContext *c = s->priv_data; const char *opts[] = { "headers", "user_agent", NULL }, **opt = opts; uint8_t *buf; int ret = 0; while (*opt) { if (av_opt_get(s->pb, *opt, AV_OPT_SEARCH_CHILDREN, &buf) >= 0) { ret = av_dict_set(&c->avio_opts, *opt, buf, AV_DICT_DONT_STRDUP_VAL); if (ret < 0) return ret; } opt++; } return ret; }
void get_shoutcast_metadata(AVFormatContext *ic) { char *value = NULL; if (av_opt_get(ic, "icy_metadata_packet", 1, (uint8_t **) &value) < 0) { value = NULL; } if (value && value[0]) { av_dict_set(&ic->metadata, ICY_METADATA, value, 0); /*int first_pos = first_char_pos(value, '\''); int last_pos = first_char_pos(value, ';') - 2; int pos = last_pos - first_pos; if (pos == 0) { return; } char temp[pos]; memcpy(temp, value + first_pos + 1 , pos); temp[pos] = '\0'; value = temp; first_pos = first_char_pos(value, '-') - 1; char artist[first_pos]; memcpy(artist, value, first_pos); artist[first_pos] = '\0'; av_dict_set(&ic->metadata, ICY_ARTIST, artist, 0); pos = strlen(value) - first_char_pos(value, '-') + 2; char album[pos]; memcpy(album, value + first_char_pos(value, '-') + 2, pos); album[pos] = '\0'; av_dict_set(&ic->metadata, ICY_TITLE, album, 0);*/ } }
static int metadata_header_get(struct http_icy_metadata *metadata, AVFormatContext *fmtctx) { uint8_t *buffer; char *icy_token; char *ptr; av_opt_get(fmtctx, "icy_metadata_headers", AV_OPT_SEARCH_CHILDREN, &buffer); if (!buffer) return -1; icy_token = strtok((char *)buffer, "\r\n"); while (icy_token != NULL) { ptr = strchr(icy_token, ':'); if (!ptr || (ptr[1] == '\0')) { icy_token = strtok(NULL, "\r\n"); continue; } ptr++; if (ptr[0] == ' ') ptr++; if ((strncmp(icy_token, "icy-name", strlen("icy-name")) == 0) && !metadata->name) metadata->name = strdup(ptr); else if ((strncmp(icy_token, "icy-description", strlen("icy-description")) == 0) && !metadata->description) metadata->description = strdup(ptr); else if ((strncmp(icy_token, "icy-genre", strlen("icy-genre")) == 0) && !metadata->genre) metadata->genre = strdup(ptr); icy_token = strtok(NULL, "\r\n"); } av_free(buffer); return 0; }
int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { AVProbeData pd = { filename ? filename : "" }; uint8_t *buf = NULL; int ret = 0, probe_size, buf_offset = 0; int score = 0; int ret2; if (!max_probe_size) max_probe_size = PROBE_BUF_MAX; else if (max_probe_size < PROBE_BUF_MIN) { av_log(logctx, AV_LOG_ERROR, "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN); return AVERROR(EINVAL); } if (offset >= max_probe_size) return AVERROR(EINVAL); if (pb->av_class) { uint8_t *mime_type_opt = NULL; char *semi; av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type_opt); pd.mime_type = (const char *)mime_type_opt; semi = pd.mime_type ? strchr(pd.mime_type, ';') : NULL; if (semi) { *semi = '\0'; } } #if 0 if (!*fmt && pb->av_class && av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type) >= 0 && mime_type) { if (!av_strcasecmp(mime_type, "audio/aacp")) { *fmt = av_find_input_format("aac"); } av_freep(&mime_type); } #endif for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt; probe_size = FFMIN(probe_size << 1, FFMAX(max_probe_size, probe_size + 1))) { score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0; /* Read probe data. */ if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0) goto fail; if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) { /* Fail if error was not end of file, otherwise, lower score. */ if (ret != AVERROR_EOF) goto fail; score = 0; ret = 0; /* error was end of file, nothing read */ } buf_offset += ret; if (buf_offset < offset) continue; pd.buf_size = buf_offset - offset; pd.buf = &buf[offset]; memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE); /* Guess file format. */ *fmt = av_probe_input_format2(&pd, 1, &score); if (*fmt) { /* This can only be true in the last iteration. */ if (score <= AVPROBE_SCORE_RETRY) { av_log(logctx, AV_LOG_WARNING, "Format %s detected only with low score of %d, " "misdetection possible!\n", (*fmt)->name, score); } else av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score); #if 0 FILE *f = fopen("probestat.tmp", "ab"); fprintf(f, "probe_size:%d format:%s score:%d filename:%s\n", probe_size, (*fmt)->name, score, filename); fclose(f); #endif } } if (!*fmt) ret = AVERROR_INVALIDDATA; fail: /* Rewind. Reuse probe buffer to avoid seeking. */ ret2 = ffio_rewind_with_probe_data(pb, &buf, buf_offset); if (ret >= 0) ret = ret2; av_freep(&pd.mime_type); return ret < 0 ? ret : score; }
int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s, AVStream *st, URLContext *handle, int packet_size, int idx) { AVFormatContext *rtpctx = NULL; int ret; AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); uint8_t *rtpflags; AVDictionary *opts = NULL; if (!rtp_format) { ret = AVERROR(ENOSYS); goto fail; } /* Allocate an AVFormatContext for each output stream */ rtpctx = avformat_alloc_context(); if (!rtpctx) { ret = AVERROR(ENOMEM); goto fail; } rtpctx->oformat = rtp_format; if (!avformat_new_stream(rtpctx, NULL)) { ret = AVERROR(ENOMEM); goto fail; } /* Pass the interrupt callback on */ rtpctx->interrupt_callback = s->interrupt_callback; /* Copy the max delay setting; the rtp muxer reads this. */ rtpctx->max_delay = s->max_delay; /* Copy other stream parameters. */ rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio; rtpctx->flags |= s->flags & AVFMT_FLAG_BITEXACT; /* Get the payload type from the codec */ if (st->id < RTP_PT_PRIVATE) rtpctx->streams[0]->id = ff_rtp_get_payload_type(s, st->codecpar, idx); else rtpctx->streams[0]->id = st->id; if (av_opt_get(s, "rtpflags", AV_OPT_SEARCH_CHILDREN, &rtpflags) >= 0) av_dict_set(&opts, "rtpflags", rtpflags, AV_DICT_DONT_STRDUP_VAL); /* Set the synchronized start time. */ rtpctx->start_time_realtime = s->start_time_realtime; avcodec_parameters_copy(rtpctx->streams[0]->codecpar, st->codecpar); rtpctx->streams[0]->time_base = st->time_base; if (handle) { ret = ffio_fdopen(&rtpctx->pb, handle); if (ret < 0) ffurl_close(handle); } else ret = ffio_open_dyn_packet_buf(&rtpctx->pb, packet_size); if (!ret) ret = avformat_write_header(rtpctx, &opts); av_dict_free(&opts); if (ret) { if (handle && rtpctx->pb) { avio_closep(&rtpctx->pb); } else if (rtpctx->pb) { ffio_free_dyn_buf(&rtpctx->pb); } avformat_free_context(rtpctx); return ret; } *out = rtpctx; return 0; fail: avformat_free_context(rtpctx); if (handle) ffurl_close(handle); return ret; }
static int parse_playlist(HLSContext *c, const char *url, struct variant *var, AVIOContext *in) { int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; int64_t duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[1024]; const char *ptr; int close_in = 0; uint8_t *new_url = NULL; if (!in) { ret = open_in(c, &in, url); if (ret < 0) return ret; close_in = 1; } if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) url = new_url; read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } if (var) { free_segment_list(var); var->finished = 0; } while (!in->eof_reached) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); key_type = KEY_NONE; has_iv = 0; if (!strcmp(info.method, "AES-128")) key_type = KEY_AES_128; if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { ff_hex_to_data(iv, info.iv + 2); has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->target_duration = atoi(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } var->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (var) var->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!var) { var = new_variant(c, 0, url, NULL); if (!var) { ret = AVERROR(ENOMEM); goto fail; } } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; seg->key_type = key_type; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { int seq = var->start_seq_no + var->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&var->segments, &var->n_segments, seg); is_segment = 0; } } } if (var) var->last_load_time = av_gettime_relative(); fail: av_free(new_url); if (close_in) avio_close(in); 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); } 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); /* 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); AVStream *ist = v->ctx->streams[j]; if (!st) { ret = AVERROR(ENOMEM); goto fail; } ff_program_add_stream_index(s, i, stream_offset + j); 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, 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; }
int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { AVProbeData pd = { filename ? filename : "" }; uint8_t *buf = NULL; int ret = 0, probe_size; if (!max_probe_size) max_probe_size = PROBE_BUF_MAX; else if (max_probe_size > PROBE_BUF_MAX) max_probe_size = PROBE_BUF_MAX; else if (max_probe_size < PROBE_BUF_MIN) return AVERROR(EINVAL); if (offset >= max_probe_size) return AVERROR(EINVAL); avio_skip(pb, offset); max_probe_size -= offset; if (pb->av_class) av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &pd.mime_type); for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt; probe_size = FFMIN(probe_size << 1, FFMAX(max_probe_size, probe_size + 1))) { int score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX / 4 : 0; /* Read probe data. */ if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0) goto fail; if ((ret = avio_read(pb, buf + pd.buf_size, probe_size - pd.buf_size)) < 0) { /* Fail if error was not end of file, otherwise, lower score. */ if (ret != AVERROR_EOF) goto fail; score = 0; ret = 0; /* error was end of file, nothing read */ } pd.buf_size += ret; pd.buf = buf; memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE); /* Guess file format. */ *fmt = av_probe_input_format2(&pd, 1, &score); if (*fmt) { /* This can only be true in the last iteration. */ if (score <= AVPROBE_SCORE_MAX / 4) { av_log(logctx, AV_LOG_WARNING, "Format detected only with low score of %d, " "misdetection possible!\n", score); } else av_log(logctx, AV_LOG_DEBUG, "Probed with size=%d and score=%d\n", probe_size, score); } } if (!*fmt) ret = AVERROR_INVALIDDATA; fail: /* Rewind. Reuse probe buffer to avoid seeking. */ if (ret < 0 || (ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0) { av_free(buf); } av_free(pd.mime_type); return ret; }
static int parse_playlist(HLSContext *c, const char *url, struct playlist *pls, AVIOContext *in) { int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; int64_t duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[MAX_URL_SIZE]; const char *ptr; int close_in = 0; uint8_t *new_url = NULL; if (!in) { AVDictionary *opts = NULL; close_in = 1; /* Some HLS servers don't like being sent the range header */ av_dict_set(&opts, "seekable", "0", 0); // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user-agent", c->user_agent, 0); av_dict_set(&opts, "cookies", c->cookies, 0); av_dict_set(&opts, "headers", c->headers, 0); ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); av_dict_free(&opts); if (ret < 0) return ret; } if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) url = new_url; read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } if (pls) { free_segment_list(pls); pls->finished = 0; } while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { struct key_info info = {{0}}; ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, &info); key_type = KEY_NONE; has_iv = 0; if (!strcmp(info.method, "AES-128")) key_type = KEY_AES_128; if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { ff_hex_to_data(iv, info.iv + 2); has_iv = 1; } av_strlcpy(key, info.uri, sizeof(key)); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { if (!pls) { if (!new_variant(c, 0, url, NULL)) { ret = AVERROR(ENOMEM); goto fail; } pls = c->playlists[c->n_playlists - 1]; } pls->target_duration = atoi(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!pls) { if (!new_variant(c, 0, url, NULL)) { ret = AVERROR(ENOMEM); goto fail; } pls = c->playlists[c->n_playlists - 1]; } pls->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (pls) pls->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { if (is_variant) { if (!new_variant(c, bandwidth, line, url)) { ret = AVERROR(ENOMEM); goto fail; } is_variant = 0; bandwidth = 0; } if (is_segment) { struct segment *seg; if (!pls) { if (!new_variant(c, 0, url, NULL)) { ret = AVERROR(ENOMEM); goto fail; } pls = c->playlists[c->n_playlists - 1]; } seg = av_malloc(sizeof(struct segment)); if (!seg) { ret = AVERROR(ENOMEM); goto fail; } seg->duration = duration; seg->key_type = key_type; if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { int seq = pls->start_seq_no + pls->n_segments; memset(seg->iv, 0, sizeof(seg->iv)); AV_WB32(seg->iv + 12, seq); } ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); dynarray_add(&pls->segments, &pls->n_segments, seg); is_segment = 0; } } } if (pls) pls->last_load_time = av_gettime(); fail: av_free(new_url); if (close_in) avio_close(in); return ret; }
static int metadata_packet_get(struct http_icy_metadata *metadata, AVFormatContext *fmtctx) { uint8_t *buffer; char *icy_token; char *ptr; char *end; av_opt_get(fmtctx, "icy_metadata_packet", AV_OPT_SEARCH_CHILDREN, &buffer); if (!buffer) return -1; icy_token = strtok((char *)buffer, ";"); while (icy_token != NULL) { ptr = strchr(icy_token, '='); if (!ptr || (ptr[1] == '\0')) { icy_token = strtok(NULL, ";"); continue; } ptr++; if (ptr[0] == '\'') ptr++; end = strrchr(ptr, '\''); if (end) *end = '\0'; if ((strncmp(icy_token, "StreamTitle", strlen("StreamTitle")) == 0) && !metadata->title) { metadata->title = ptr; /* Dash separates artist from title, if no dash assume all is title */ ptr = strstr(ptr, " - "); if (ptr) { *ptr = '\0'; metadata->title = strdup(metadata->title); *ptr = ' '; metadata->artist = strdup(ptr + 3); } else metadata->title = strdup(metadata->title); } else if ((strncmp(icy_token, "StreamUrl", strlen("StreamUrl")) == 0) && !metadata->artwork_url) { metadata->artwork_url = strdup(ptr); } if (end) *end = '\''; icy_token = strtok(NULL, ";"); } av_free(buffer); if (metadata->title) metadata->hash = djb_hash(metadata->title, strlen(metadata->title)); return 0; }
static void process_client(AVIOContext *client, const char *in_uri) { AVIOContext *input = NULL; uint8_t buf[1024]; int ret, n, reply_code; uint8_t *resource = NULL; while ((ret = avio_handshake(client)) > 0) { av_opt_get(client, "resource", AV_OPT_SEARCH_CHILDREN, &resource); // check for strlen(resource) is necessary, because av_opt_get() // may return empty string. if (resource && strlen(resource)) break; av_freep(&resource); } if (ret < 0) goto end; av_log(client, AV_LOG_TRACE, "resource=%p\n", resource); if (resource && resource[0] == '/' && !strcmp((resource + 1), in_uri)) { reply_code = 200; } else { reply_code = AVERROR_HTTP_NOT_FOUND; } if ((ret = av_opt_set_int(client, "reply_code", reply_code, AV_OPT_SEARCH_CHILDREN)) < 0) { av_log(client, AV_LOG_ERROR, "Failed to set reply_code: %s.\n", av_err2str(ret)); goto end; } av_log(client, AV_LOG_TRACE, "Set reply code to %d\n", reply_code); while ((ret = avio_handshake(client)) > 0); if (ret < 0) goto end; fprintf(stderr, "Handshake performed.\n"); if (reply_code != 200) goto end; fprintf(stderr, "Opening input file.\n"); if ((ret = avio_open2(&input, in_uri, AVIO_FLAG_READ, NULL, NULL)) < 0) { av_log(input, AV_LOG_ERROR, "Failed to open input: %s: %s.\n", in_uri, av_err2str(ret)); goto end; } for (;;) { n = avio_read(input, buf, sizeof(buf)); if (n < 0) { if (n == AVERROR_EOF) break; av_log(input, AV_LOG_ERROR, "Error reading from input: %s.\n", av_err2str(n)); break; } avio_write(client, buf, n); avio_flush(client); } end: fprintf(stderr, "Flushing client\n"); avio_flush(client); fprintf(stderr, "Closing client\n"); avio_close(client); fprintf(stderr, "Closing input\n"); avio_close(input); av_freep(&resource); }