diff --git a/avconv.c b/avconv.c index 76d8def806a2cd3b3ff8feda00d0ff5657aee33e..a019ffaf6f79a8c5caf8027d188c5f45f7a2c586 100644 --- a/avconv.c +++ b/avconv.c @@ -588,12 +588,14 @@ static int read_key(void) return -1; } -static int decode_interrupt_cb(void) +static int decode_interrupt_cb(void *ctx) { q_pressed += read_key() == 'q'; return q_pressed > 1; } +static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; + void exit_program(int ret) { int i; @@ -2336,6 +2338,7 @@ static int transcode_init(OutputFile *output_files, /* open files and write file headers */ for (i = 0; i < nb_output_files; i++) { os = output_files[i].ctx; + os->interrupt_callback = int_cb; if (avformat_write_header(os, &output_files[i].opts) < 0) { snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?)", i); ret = AVERROR(EINVAL); @@ -3010,7 +3013,7 @@ static void dump_attachment(AVStream *st, const char *filename) assert_file_overwrite(filename); - if ((ret = avio_open (&out, filename, AVIO_FLAG_WRITE)) < 0) { + if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) { av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n", filename); exit_program(1); @@ -3068,6 +3071,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena av_dict_set(&format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0); ic->flags |= AVFMT_FLAG_NONBLOCK; + ic->interrupt_callback = int_cb; /* open the input file with generic libav function */ err = avformat_open_input(&ic, filename, file_iformat, &format_opts); @@ -3197,12 +3201,12 @@ static int get_preset_file_2(const char *preset_name, const char *codec_name, AV if (codec_name) { snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i], i != 1 ? "" : "/.avconv", codec_name, preset_name); - ret = avio_open(s, filename, AVIO_FLAG_READ); + ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); } if (ret) { snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i], i != 1 ? "" : "/.avconv", preset_name); - ret = avio_open(s, filename, AVIO_FLAG_READ); + ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); } } return ret; @@ -3588,8 +3592,9 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) { int i, err; - AVFormatContext *ic = NULL; + AVFormatContext *ic = avformat_alloc_context(); + ic->interrupt_callback = int_cb; err = avformat_open_input(&ic, filename, NULL, NULL); if (err < 0) return err; @@ -3638,6 +3643,7 @@ static void opt_output_file(void *optctx, const char *filename) } file_oformat= oc->oformat; + oc->interrupt_callback = int_cb; if (!strcmp(file_oformat->name, "ffm") && av_strstart(filename, "http:", NULL)) { @@ -3729,7 +3735,7 @@ static void opt_output_file(void *optctx, const char *filename) const char *p; int64_t len; - if ((err = avio_open(&pb, o->attachments[i], AVIO_FLAG_READ)) < 0) { + if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) { av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n", o->attachments[i]); exit_program(1); @@ -3779,7 +3785,9 @@ static void opt_output_file(void *optctx, const char *filename) assert_file_overwrite(filename); /* open the file */ - if ((err = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE)) < 0) { + if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, + &oc->interrupt_callback, + &output_files[nb_output_files - 1].opts)) < 0) { print_error(filename, err); exit_program(1); } @@ -4350,12 +4358,6 @@ int main(int argc, char **argv) av_register_all(); avformat_network_init(); -#if HAVE_ISATTY - if(isatty(STDIN_FILENO)) - avio_set_interrupt_cb(decode_interrupt_cb); -#endif - - show_banner(); /* parse options */ parse_options(&o, argc, argv, options, opt_output_file); diff --git a/configure b/configure index 2daa079b573161f40a5e76715232ac59d470280a..d0376bb391f5f443f4f5f0b4472f85a787eaf82e 100755 --- a/configure +++ b/configure @@ -2583,7 +2583,6 @@ case $target_os in disable network else target_os=mingw32 - enable_weak w32threads fi LIBTARGET=i386 if enabled x86_64; then @@ -2999,6 +2998,10 @@ if ! disabled vda; then fi fi +if ! disabled w32threads && ! enabled pthreads; then + check_func _beginthreadex && enable w32threads +fi + # check for some common methods of building with pthread support # do this before the optional library checks as some of them require pthreads if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then diff --git a/doc/APIchanges b/doc/APIchanges index 03f7d460d2943d1f441e2ce6f85d83178c040334..2ce14618fa783d44edd831cb0903e85ac8d66fb7 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -19,6 +19,16 @@ API changes, most recent first: 2011-10-20 - b35e9e1 - lavu 51.22.0 Add av_strtok() to avstring.h. +2011-11-13 - lavf 53.15.0 + New interrupt callback API, allowing per-AVFormatContext/AVIOContext + interrupt callbacks. + 6aa0b98 Add AVIOInterruptCB struct and the interrupt_callback field to + AVFormatContext. + 1dee0ac Add avio_open2() with additional parameters. Those are + an interrupt callback and an options AVDictionary. + This will allow passing AVOptions to protocols after lavf + 54.0. + 2011-11-xx - xxxxxxx - lavu 51.16.0 Add av_timegm() diff --git a/ffmpeg.c b/ffmpeg.c index 9895fb39703646c1418248ffded0889a5bc3706c..507c35dba4ec281ffcef3c5d76cd0641a5b9ba6f 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -635,11 +635,13 @@ static int read_key(void) return -1; } -static int decode_interrupt_cb(void) +static int decode_interrupt_cb(void *ctx) { return received_nb_signals > 1; } +static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; + void av_noreturn exit_program(int ret) { int i; @@ -2403,6 +2405,7 @@ static int transcode_init(OutputFile *output_files, int nb_output_files, /* open files and write file headers */ for (i = 0; i < nb_output_files; i++) { os = output_files[i].ctx; + os->interrupt_callback = int_cb; if (avformat_write_header(os, &output_files[i].opts) < 0) { snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?)", i); ret = AVERROR(EINVAL); @@ -2495,7 +2498,6 @@ static int transcode(OutputFile *output_files, int nb_output_files, if (!using_stdin) { av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n"); - avio_set_interrupt_cb(decode_interrupt_cb); } timer_start = av_gettime(); @@ -3243,7 +3245,7 @@ static void dump_attachment(AVStream *st, const char *filename) assert_file_overwrite(filename); - if ((ret = avio_open (&out, filename, AVIO_FLAG_WRITE)) < 0) { + if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) { av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n", filename); exit_program(1); @@ -3307,6 +3309,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena ic->subtitle_codec_id= subtitle_codec_name ? find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : CODEC_ID_NONE; ic->flags |= AVFMT_FLAG_NONBLOCK; + ic->interrupt_callback = int_cb; if (loop_input) { av_log(NULL, AV_LOG_WARNING, "-loop_input is deprecated, use -loop 1\n"); @@ -3438,12 +3441,12 @@ static int get_preset_file_2(const char *preset_name, const char *codec_name, AV if (codec_name) { snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i], i != 1 ? "" : "/.avconv", codec_name, preset_name); - ret = avio_open(s, filename, AVIO_FLAG_READ); + ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); } if (ret) { snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i], i != 1 ? "" : "/.avconv", preset_name); - ret = avio_open(s, filename, AVIO_FLAG_READ); + ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); } } return ret; @@ -3856,8 +3859,9 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) { int i, err; - AVFormatContext *ic = NULL; + AVFormatContext *ic = avformat_alloc_context(); + ic->interrupt_callback = int_cb; err = avformat_open_input(&ic, filename, NULL, NULL); if (err < 0) return err; @@ -3908,6 +3912,7 @@ static void opt_output_file(void *optctx, const char *filename) exit_program(1); } file_oformat= oc->oformat; + oc->interrupt_callback = int_cb; if (!strcmp(file_oformat->name, "ffm") && av_strstart(filename, "http:", NULL)) { @@ -4019,7 +4024,7 @@ static void opt_output_file(void *optctx, const char *filename) const char *p; int64_t len; - if ((err = avio_open(&pb, o->attachments[i], AVIO_FLAG_READ)) < 0) { + if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) { av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n", o->attachments[i]); exit_program(1); @@ -4069,7 +4074,9 @@ static void opt_output_file(void *optctx, const char *filename) assert_file_overwrite(filename); /* open the file */ - if ((err = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE)) < 0) { + if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, + &oc->interrupt_callback, + &output_files[nb_output_files - 1].opts)) < 0) { print_error(filename, err); exit_program(1); } @@ -4725,12 +4732,6 @@ int main(int argc, char **argv) av_register_all(); avformat_network_init(); -#if HAVE_ISATTY - if(isatty(STDIN_FILENO)) - avio_set_interrupt_cb(decode_interrupt_cb); -#endif - - show_banner(); term_init(); diff --git a/ffplay.c b/ffplay.c index 2ce7ea2047c9a55417a06b052f686848711c1c67..46cf6a12d802229d41e91a501cde9efc4a55da64 100644 --- a/ffplay.c +++ b/ffplay.c @@ -2414,7 +2414,7 @@ static void stream_component_close(VideoState *is, int stream_index) variable instead of a thread local variable */ static VideoState *global_video_state; -static int decode_interrupt_cb(void) +static int decode_interrupt_cb(void *ctx) { return (global_video_state && global_video_state->abort_request); } @@ -2439,8 +2439,9 @@ static int read_thread(void *arg) is->subtitle_stream = -1; global_video_state = is; - avio_set_interrupt_cb(decode_interrupt_cb); + ic = avformat_alloc_context(); + ic->interrupt_callback.callback = decode_interrupt_cb; err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts); if (err < 0) { print_error(is->filename, err); diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c index fe6552487070c83e0dac588ee6ebf0ee6c3caa64..ebdbb5eaecec21fe9d1b4ea925f132248ba9de46 100644 --- a/libavcodec/cinepak.c +++ b/libavcodec/cinepak.c @@ -147,7 +147,7 @@ static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, for (x=strip->x1; x < strip->x2; x+=4) { if ((chunk_id & 0x01) && !(mask >>= 1)) { if ((data + 4) > eod) - return -1; + return AVERROR_INVALIDDATA; flag = AV_RB32 (data); data += 4; @@ -157,7 +157,7 @@ static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, if (!(chunk_id & 0x01) || (flag & mask)) { if (!(chunk_id & 0x02) && !(mask >>= 1)) { if ((data + 4) > eod) - return -1; + return AVERROR_INVALIDDATA; flag = AV_RB32 (data); data += 4; @@ -166,7 +166,7 @@ static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, if ((chunk_id & 0x02) || (~flag & mask)) { if (data >= eod) - return -1; + return AVERROR_INVALIDDATA; codebook = &strip->v1_codebook[*data++]; s->frame.data[0][iy[0] + 0] = codebook->y0; @@ -207,7 +207,7 @@ static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, } else if (flag & mask) { if ((data + 4) > eod) - return -1; + return AVERROR_INVALIDDATA; codebook = &strip->v4_codebook[*data++]; s->frame.data[0][iy[0] + 0] = codebook->y0; @@ -269,16 +269,16 @@ static int cinepak_decode_strip (CinepakContext *s, int chunk_id, chunk_size; /* coordinate sanity checks */ - if (strip->x2 > s->width || - strip->y2 > s->height || + if (strip->x2 > s->width || + strip->y2 > s->height || strip->x1 >= strip->x2 || strip->y1 >= strip->y2) - return -1; + return AVERROR_INVALIDDATA; while ((data + 4) <= eod) { chunk_id = data[0]; chunk_size = AV_RB24 (&data[1]) - 4; if(chunk_size < 0) - return -1; + return AVERROR_INVALIDDATA; data += 4; chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size; @@ -311,7 +311,7 @@ static int cinepak_decode_strip (CinepakContext *s, data += chunk_size; } - return -1; + return AVERROR_INVALIDDATA; } static int cinepak_decode (CinepakContext *s) @@ -322,7 +322,7 @@ static int cinepak_decode (CinepakContext *s) int encoded_buf_size; if (s->size < 10) - return -1; + return AVERROR_INVALIDDATA; frame_flags = s->data[0]; num_strips = AV_RB16 (&s->data[8]); @@ -330,9 +330,9 @@ static int cinepak_decode (CinepakContext *s) /* if this is the first frame, check for deviant Sega FILM data */ if (s->sega_film_skip_bytes == -1) { - if (!encoded_buf_size){ + if (!encoded_buf_size) { av_log_ask_for_sample(s->avctx, "encoded_buf_size is 0"); - return -1; + return AVERROR_INVALIDDATA; } if (encoded_buf_size != s->size && (s->size % encoded_buf_size) != 0) { /* If the encoded frame size differs from the frame size as indicated @@ -363,7 +363,7 @@ static int cinepak_decode (CinepakContext *s) for (i=0; i < num_strips; i++) { if ((s->data + 12) > eod) - return -1; + return AVERROR_INVALIDDATA; s->strips[i].id = s->data[0]; s->strips[i].y1 = y0; @@ -375,8 +375,8 @@ static int cinepak_decode (CinepakContext *s) s->frame.key_frame = 1; strip_size = AV_RB24 (&s->data[1]) - 12; - if(strip_size < 0) - return -1; + if (strip_size < 0) + return AVERROR_INVALIDDATA; s->data += 12; strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size; @@ -427,7 +427,7 @@ static int cinepak_decode_frame(AVCodecContext *avctx, AVPacket *avpkt) { const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; + int ret = 0, buf_size = avpkt->size; CinepakContext *s = avctx->priv_data; s->data = buf; @@ -436,9 +436,9 @@ static int cinepak_decode_frame(AVCodecContext *avctx, s->frame.reference = 3; s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; - if (avctx->reget_buffer(avctx, &s->frame)) { + if ((ret = avctx->reget_buffer(avctx, &s->frame))) { av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); - return -1; + return ret; } if (s->palette_video) { diff --git a/libavformat/allformats.c b/libavformat/allformats.c index c4b27e43cdd1ce39e4f49f46132bd69c91c60de2..31fa5060f748eb0c1de8708285f86d83d122d025 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -259,6 +259,7 @@ void av_register_all(void) REGISTER_PROTOCOL (FILE, file); REGISTER_PROTOCOL (GOPHER, gopher); REGISTER_PROTOCOL (HTTP, http); + REGISTER_PROTOCOL (HTTPPROXY, httpproxy); REGISTER_PROTOCOL (HTTPS, https); REGISTER_PROTOCOL (MMSH, mmsh); REGISTER_PROTOCOL (MMST, mmst); diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c index 7c41d9893c5433dde9e94a280041dd7304a1f290..1694096d9ba11ac5c3c3af24a77b69bc908d3817 100644 --- a/libavformat/applehttp.c +++ b/libavformat/applehttp.c @@ -644,7 +644,8 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index, for (i = 0; i < c->n_variants; i++) { /* Reset reading */ struct variant *var = c->variants[i]; - int64_t pos = av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ? + int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 : + av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ? s->streams[stream_index]->time_base.den : AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP); diff --git a/libavformat/avio.c b/libavformat/avio.c index 879844aefc4ca390ddc0998c017bb45fc7c9b456..b2b39b32d76f83f51bb4ce759b1a569bee65951d 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -83,9 +83,11 @@ const AVClass ffurl_context_class = { }; /*@}*/ -static int default_interrupt_cb(void); +#if FF_API_OLD_INTERRUPT_CB +static int default_interrupt_cb(void); int (*url_interrupt_cb)(void) = default_interrupt_cb; +#endif URLProtocol *av_protocol_next(URLProtocol *p) { @@ -444,6 +446,7 @@ int ffurl_get_file_handle(URLContext *h) return h->prot->url_get_file_handle(h); } +#if FF_API_OLD_INTERRUPT_CB static int default_interrupt_cb(void) { return 0; @@ -455,13 +458,18 @@ void avio_set_interrupt_cb(int (*interrupt_cb)(void)) interrupt_cb = default_interrupt_cb; url_interrupt_cb = interrupt_cb; } +#endif int ff_check_interrupt(AVIOInterruptCB *cb) { int ret; if (cb && cb->callback && (ret = cb->callback(cb->opaque))) return ret; +#if FF_API_OLD_INTERRUPT_CB return url_interrupt_cb(); +#else + return 0; +#endif } #if FF_API_OLD_AVIO diff --git a/libavformat/avio.h b/libavformat/avio.h index 14f3b7b2924b6d89c27854af7c67af213232725c..88fe1577ff13a9727a1f7b5a845bd8874210c01e 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -386,13 +386,17 @@ attribute_deprecated int url_exist(const char *url); */ int avio_check(const char *url, int flags); +#if FF_API_OLD_INTERRUPT_CB /** * The callback is called in blocking functions to test regulary if * asynchronous interruption is needed. AVERROR_EXIT is returned * in this case by the interrupted function. 'NULL' means no interrupt * callback is given. + * @deprecated Use interrupt_callback in AVFormatContext/avio_open2 + * instead. */ -void avio_set_interrupt_cb(int (*interrupt_cb)(void)); +attribute_deprecated void avio_set_interrupt_cb(int (*interrupt_cb)(void)); +#endif /** * Allocate and initialize an AVIOContext for buffered I/O. It must be later diff --git a/libavformat/http.c b/libavformat/http.c index ad4018085c6f887b1717e4290a34e57f7843537e..d45ef226161f74166c6a28337928e5446e5a5234 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -110,6 +110,15 @@ static int http_open_cnx(URLContext *h) path1, sizeof(path1), s->location); ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL); + if (!strcmp(proto, "https")) { + lower_proto = "tls"; + use_proxy = 0; + if (port < 0) + port = 443; + } + if (port < 0) + port = 80; + if (path1[0] == '\0') path = "/"; else @@ -124,13 +133,6 @@ static int http_open_cnx(URLContext *h) av_url_split(NULL, 0, proxyauth, sizeof(proxyauth), hostname, sizeof(hostname), &port, NULL, 0, proxy_path); } - if (!strcmp(proto, "https")) { - lower_proto = "tls"; - if (port < 0) - port = 443; - } - if (port < 0) - port = 80; ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL); err = ffurl_open(&hd, buf, AVIO_FLAG_READ_WRITE, @@ -413,10 +415,33 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, } -static int http_read(URLContext *h, uint8_t *buf, int size) +static int http_buf_read(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; int len; + /* read bytes from input buffer first */ + len = s->buf_end - s->buf_ptr; + if (len > 0) { + if (len > size) + len = size; + memcpy(buf, s->buf_ptr, len); + s->buf_ptr += len; + } else { + if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize) + return AVERROR_EOF; + len = ffurl_read(s->hd, buf, size); + } + if (len > 0) { + s->off += len; + if (s->chunksize > 0) + s->chunksize -= len; + } + return len; +} + +static int http_read(URLContext *h, uint8_t *buf, int size) +{ + HTTPContext *s = h->priv_data; if (s->chunksize >= 0) { if (!s->chunksize) { @@ -439,24 +464,7 @@ static int http_read(URLContext *h, uint8_t *buf, int size) } size = FFMIN(size, s->chunksize); } - /* read bytes from input buffer first */ - len = s->buf_end - s->buf_ptr; - if (len > 0) { - if (len > size) - len = size; - memcpy(buf, s->buf_ptr, len); - s->buf_ptr += len; - } else { - if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize) - return AVERROR_EOF; - len = ffurl_read(s->hd, buf, size); - } - if (len > 0) { - s->off += len; - if (s->chunksize > 0) - s->chunksize -= len; - } - return len; + return http_buf_read(h, buf, size); } /* used only when posting data */ @@ -572,3 +580,118 @@ URLProtocol ff_https_protocol = { .priv_data_class = &https_context_class, }; #endif + +#if CONFIG_HTTPPROXY_PROTOCOL +static int http_proxy_close(URLContext *h) +{ + HTTPContext *s = h->priv_data; + if (s->hd) + ffurl_close(s->hd); + return 0; +} + +static int http_proxy_open(URLContext *h, const char *uri, int flags) +{ + HTTPContext *s = h->priv_data; + char hostname[1024], hoststr[1024]; + char auth[1024], pathbuf[1024], *path; + char line[1024], lower_url[100]; + int port, ret = 0; + HTTPAuthType cur_auth_type; + char *authstr; + + h->is_streamed = 1; + + av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, + pathbuf, sizeof(pathbuf), uri); + ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL); + path = pathbuf; + if (*path == '/') + path++; + + ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port, + NULL); +redo: + ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, + &h->interrupt_callback, NULL); + if (ret < 0) + return ret; + + authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth, + path, "CONNECT"); + snprintf(s->buffer, sizeof(s->buffer), + "CONNECT %s HTTP/1.1\r\n" + "Host: %s\r\n" + "Connection: close\r\n" + "%s%s" + "\r\n", + path, + hoststr, + authstr ? "Proxy-" : "", authstr ? authstr : ""); + av_freep(&authstr); + + if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0) + goto fail; + + s->buf_ptr = s->buffer; + s->buf_end = s->buffer; + s->line_count = 0; + s->filesize = -1; + cur_auth_type = s->proxy_auth_state.auth_type; + + for (;;) { + int new_loc; + // Note: This uses buffering, potentially reading more than the + // HTTP header. If tunneling a protocol where the server starts + // the conversation, we might buffer part of that here, too. + // Reading that requires using the proper ffurl_read() function + // on this URLContext, not using the fd directly (as the tls + // protocol does). This shouldn't be an issue for tls though, + // since the client starts the conversation there, so there + // is no extra data that we might buffer up here. + if (http_get_line(s, line, sizeof(line)) < 0) { + ret = AVERROR(EIO); + goto fail; + } + + av_dlog(h, "header='%s'\n", line); + + ret = process_line(h, line, s->line_count, &new_loc); + if (ret < 0) + goto fail; + if (ret == 0) + break; + s->line_count++; + } + if (s->http_code == 407 && cur_auth_type == HTTP_AUTH_NONE && + s->proxy_auth_state.auth_type != HTTP_AUTH_NONE) { + ffurl_close(s->hd); + s->hd = NULL; + goto redo; + } + + if (s->http_code < 400) + return 0; + ret = AVERROR(EIO); + +fail: + http_proxy_close(h); + return ret; +} + +static int http_proxy_write(URLContext *h, const uint8_t *buf, int size) +{ + HTTPContext *s = h->priv_data; + return ffurl_write(s->hd, buf, size); +} + +URLProtocol ff_httpproxy_protocol = { + .name = "httpproxy", + .url_open = http_proxy_open, + .url_read = http_buf_read, + .url_write = http_proxy_write, + .url_close = http_proxy_close, + .url_get_file_handle = http_get_file_handle, + .priv_data_size = sizeof(HTTPContext), +}; +#endif diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index e73158f12ce189c9b4bb0653d9761323c0d0cd9b..8935f56369497e7deb32ada6126d18f1c62287ee 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -74,6 +74,7 @@ typedef struct RTMPContext { int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call uint8_t flv_header[11]; ///< partial incoming flv packet header int flv_header_bytes; ///< number of initialized bytes in flv_header + int nb_invokes; ///< keeps track of invoke messages } RTMPContext; #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing @@ -166,7 +167,7 @@ static void gen_release_stream(URLContext *s, RTMPContext *rt) av_log(s, AV_LOG_DEBUG, "Releasing stream...\n"); p = pkt.data; ff_amf_write_string(&p, "releaseStream"); - ff_amf_write_number(&p, 2.0); + ff_amf_write_number(&p, ++rt->nb_invokes); ff_amf_write_null(&p); ff_amf_write_string(&p, rt->playpath); @@ -189,7 +190,7 @@ static void gen_fcpublish_stream(URLContext *s, RTMPContext *rt) av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n"); p = pkt.data; ff_amf_write_string(&p, "FCPublish"); - ff_amf_write_number(&p, 3.0); + ff_amf_write_number(&p, ++rt->nb_invokes); ff_amf_write_null(&p); ff_amf_write_string(&p, rt->playpath); @@ -212,7 +213,7 @@ static void gen_fcunpublish_stream(URLContext *s, RTMPContext *rt) av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n"); p = pkt.data; ff_amf_write_string(&p, "FCUnpublish"); - ff_amf_write_number(&p, 5.0); + ff_amf_write_number(&p, ++rt->nb_invokes); ff_amf_write_null(&p); ff_amf_write_string(&p, rt->playpath); @@ -234,7 +235,7 @@ static void gen_create_stream(URLContext *s, RTMPContext *rt) p = pkt.data; ff_amf_write_string(&p, "createStream"); - ff_amf_write_number(&p, rt->is_input ? 3.0 : 4.0); + ff_amf_write_number(&p, ++rt->nb_invokes); ff_amf_write_null(&p); ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index f264efe92e4627f188d2597db1d5bfe70bf4d0aa..95a1edaa5555e3107918daffb7c2623ba5f1cd4a 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -429,7 +429,7 @@ static void finalize_packet(RTPDemuxContext *s, AVPacket *pkt, uint32_t timestam if (timestamp == RTP_NOTS_VALUE) return; - if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE) { + if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE && s->ic->nb_streams > 1) { int64_t addend; int delta_timestamp; @@ -444,7 +444,13 @@ static void finalize_packet(RTPDemuxContext *s, AVPacket *pkt, uint32_t timestam if (!s->base_timestamp) s->base_timestamp = timestamp; - pkt->pts = s->range_start_offset + timestamp - s->base_timestamp; + /* assume that the difference is INT32_MIN < x < INT32_MAX, but allow the first timestamp to exceed INT32_MAX */ + if (!s->timestamp) + s->unwrapped_timestamp += timestamp; + else + s->unwrapped_timestamp += (int32_t)(timestamp - s->timestamp); + s->timestamp = timestamp; + pkt->pts = s->unwrapped_timestamp + s->range_start_offset - s->base_timestamp; } static int rtp_parse_packet_internal(RTPDemuxContext *s, AVPacket *pkt, diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index dbb45f5709b63fac8c7893e5dbe9880ec44c635f..eb468be9e5ecabf3d8116ceb1b641316fa46de2b 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -151,6 +151,7 @@ struct RTPDemuxContext { uint32_t timestamp; uint32_t base_timestamp; uint32_t cur_timestamp; + int64_t unwrapped_timestamp; int64_t range_start_offset; int max_payload_size; struct MpegTSContext *ts; /* only used for MP2T payloads */ diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index f55b8cf2a2ff54e3465bf82e2a46fed137f14ea2..8699f77918eca9fe3d77dc4a97f05bb5f57a3207 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -52,6 +52,8 @@ static int rtsp_read_play(AVFormatContext *s) rtpctx->last_rtcp_ntp_time = AV_NOPTS_VALUE; rtpctx->first_rtcp_ntp_time = AV_NOPTS_VALUE; rtpctx->base_timestamp = 0; + rtpctx->timestamp = 0; + rtpctx->unwrapped_timestamp = 0; rtpctx->rtcp_ts_offset = 0; } } diff --git a/libavformat/segafilm.c b/libavformat/segafilm.c index 1ae105eb77ba0013c482f4405dab611b23111c55..0199ee1f5f55629153a9bbbd7eb05291141cc917 100644 --- a/libavformat/segafilm.c +++ b/libavformat/segafilm.c @@ -34,6 +34,7 @@ #define FDSC_TAG MKBETAG('F', 'D', 'S', 'C') #define STAB_TAG MKBETAG('S', 'T', 'A', 'B') #define CVID_TAG MKBETAG('c', 'v', 'i', 'd') +#define RAW_TAG MKBETAG('r', 'a', 'w', ' ') typedef struct { int stream; @@ -129,8 +130,11 @@ static int film_read_header(AVFormatContext *s, if (AV_RB32(&scratch[8]) == CVID_TAG) { film->video_type = CODEC_ID_CINEPAK; - } else + } else if (AV_RB32(&scratch[8]) == RAW_TAG) { + film->video_type = CODEC_ID_RAWVIDEO; + } else { film->video_type = CODEC_ID_NONE; + } /* initialize the decoder streams */ if (film->video_type) { @@ -143,6 +147,15 @@ static int film_read_header(AVFormatContext *s, st->codec->codec_tag = 0; /* no fourcc */ st->codec->width = AV_RB32(&scratch[16]); st->codec->height = AV_RB32(&scratch[12]); + + if (film->video_type == CODEC_ID_RAWVIDEO) { + if (scratch[20] == 24) { + st->codec->pix_fmt = PIX_FMT_RGB24; + } else { + av_log(s, AV_LOG_ERROR, "raw video is using unhandled %dbpp\n", scratch[20]); + return -1; + } + } } if (film->audio_type) { diff --git a/libavformat/tls.c b/libavformat/tls.c index 72c2b850166b4b4b065dd491e2d7152a4cceaf99..339b799322bc024456a417ae1a06b88f8624d4ae 100644 --- a/libavformat/tls.c +++ b/libavformat/tls.c @@ -111,9 +111,15 @@ static int tls_open(URLContext *h, const char *uri, int flags) char buf[200], host[200]; int numerichost = 0; struct addrinfo hints = { 0 }, *ai = NULL; + const char *proxy_path; + int use_proxy; ff_tls_init(); + proxy_path = getenv("http_proxy"); + use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && + av_strstart(proxy_path, "http://", NULL); + av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri); ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, NULL); @@ -123,6 +129,17 @@ static int tls_open(URLContext *h, const char *uri, int flags) freeaddrinfo(ai); } + if (use_proxy) { + char proxy_host[200], proxy_auth[200], dest[200]; + int proxy_port; + av_url_split(NULL, 0, proxy_auth, sizeof(proxy_auth), + proxy_host, sizeof(proxy_host), &proxy_port, NULL, 0, + proxy_path); + ff_url_join(dest, sizeof(dest), NULL, NULL, host, port, NULL); + ff_url_join(buf, sizeof(buf), "httpproxy", proxy_auth, proxy_host, + proxy_port, "/%s", dest); + } + ret = ffurl_open(&c->tcp, buf, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, NULL); if (ret) diff --git a/libavformat/version.h b/libavformat/version.h index 954d87a88e3f6e9c1109eedadba4b7118d5afbe9..5c7ed6863e06039f2f9a8c6476e62281b5690d78 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -24,7 +24,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 53 -#define LIBAVFORMAT_VERSION_MINOR 20 +#define LIBAVFORMAT_VERSION_MINOR 21 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -113,5 +113,8 @@ #ifndef FF_API_REORDER_PRIVATE #define FF_API_REORDER_PRIVATE (LIBAVFORMAT_VERSION_MAJOR < 54) #endif +#ifndef FF_API_OLD_INTERRUPT_CB +#define FF_API_OLD_INTERRUPT_CB (LIBAVFORMAT_VERSION_MAJOR < 54) +#endif #endif /* AVFORMAT_VERSION_H */ diff --git a/tests/lavf-regression.sh b/tests/lavf-regression.sh index 292845d4e459e4840aabd2807d88d592b97f52cd..1c579060cc4085f1691c51c58d34074b958ee9c1 100755 --- a/tests/lavf-regression.sh +++ b/tests/lavf-regression.sh @@ -71,7 +71,7 @@ do_lavf mxf_d10 "-ar 48000 -ac 2 -r 25 -s 720x576 -vf pad=720:608:0:32 -vcodec m fi if [ -n "$do_ts" ] ; then -do_lavf ts "-ab 64k" +do_lavf ts "-ab 64k -mpegts_transport_stream_id 42" fi if [ -n "$do_swf" ] ; then diff --git a/tests/ref/lavf/ts b/tests/ref/lavf/ts index 3b2dad1b5e0a394e7dabad26baf007c77a9e7fe5..018d61813a3337c00faca19cc475c68aa294a821 100644 --- a/tests/ref/lavf/ts +++ b/tests/ref/lavf/ts @@ -1,3 +1,3 @@ -151774afed45b19da9b7e83613a1e72b *./tests/data/lavf/lavf.ts +024f0cdd4c51a158b2a38b901d2ed2e5 *./tests/data/lavf/lavf.ts 406644 ./tests/data/lavf/lavf.ts ./tests/data/lavf/lavf.ts CRC=0x133216c1