From 7ebe3962f399dcddc852bda92e595b0152c3701d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 16 Aug 2012 14:24:26 +0300 Subject: [PATCH 01/10] Add missing includes for code relying on external libraries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- libavcodec/libopenjpegdec.c | 1 + libavcodec/libopenjpegenc.c | 1 + libavcodec/libschroedinger.c | 1 + libavcodec/libschroedingerdec.c | 4 ++++ libavcodec/libxavs.c | 2 ++ libavfilter/vf_frei0r.c | 6 ++++++ libavfilter/vf_libopencv.c | 1 + 7 files changed, 16 insertions(+) diff --git a/libavcodec/libopenjpegdec.c b/libavcodec/libopenjpegdec.c index 17312ffbd4..53197b5f78 100644 --- a/libavcodec/libopenjpegdec.c +++ b/libavcodec/libopenjpegdec.c @@ -27,6 +27,7 @@ #define OPJ_STATIC #include +#include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c index 93c82cf634..ed2ae3ac4a 100644 --- a/libavcodec/libopenjpegenc.c +++ b/libavcodec/libopenjpegenc.c @@ -27,6 +27,7 @@ #define OPJ_STATIC #include +#include "libavutil/common.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" diff --git a/libavcodec/libschroedinger.c b/libavcodec/libschroedinger.c index 2046761713..68e925cabc 100644 --- a/libavcodec/libschroedinger.c +++ b/libavcodec/libschroedinger.c @@ -24,6 +24,7 @@ */ #include "libschroedinger.h" +#include "libavutil/mem.h" static const SchroVideoFormatInfo ff_schro_video_format_info[] = { { 640, 480, 24000, 1001}, diff --git a/libavcodec/libschroedingerdec.c b/libavcodec/libschroedingerdec.c index 7d942e77d0..110e8d0ae1 100644 --- a/libavcodec/libschroedingerdec.c +++ b/libavcodec/libschroedingerdec.c @@ -27,8 +27,12 @@ * (http://dirac.sourceforge.net/specification.html). */ +#include + #include "libavutil/imgutils.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "libschroedinger.h" diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c index 0e1c3869a1..6cfb1366f0 100644 --- a/libavcodec/libxavs.c +++ b/libavcodec/libxavs.c @@ -28,6 +28,8 @@ #include #include "avcodec.h" #include "internal.h" +#include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #define END_OF_STREAM 0x001 diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c index 606c5e2d32..2f4e47c734 100644 --- a/libavfilter/vf_frei0r.c +++ b/libavfilter/vf_frei0r.c @@ -26,9 +26,15 @@ #include #include +#include +#include +#include +#include "config.h" #include "libavutil/avstring.h" #include "libavutil/imgutils.h" +#include "libavutil/internal.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "avfilter.h" #include "formats.h" diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c index ea6ebe1b16..fc6dfbc52e 100644 --- a/libavfilter/vf_libopencv.c +++ b/libavfilter/vf_libopencv.c @@ -28,6 +28,7 @@ #include #include #include "libavutil/avstring.h" +#include "libavutil/common.h" #include "libavutil/file.h" #include "avfilter.h" #include "formats.h" From e5f2731c736c992948ca7e344ad7cfc93168a03f Mon Sep 17 00:00:00 2001 From: Jordi Ortiz Date: Thu, 16 Aug 2012 16:04:48 +0200 Subject: [PATCH 02/10] rtmp: Add support for receiving incoming streams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- doc/protocols.texi | 5 + libavformat/rtmpproto.c | 513 +++++++++++++++++++++++++++++++++++++++- libavformat/version.h | 4 +- 3 files changed, 515 insertions(+), 7 deletions(-) diff --git a/doc/protocols.texi b/doc/protocols.texi index ea5706fbea..086a249a13 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -188,6 +188,11 @@ application specified in @var{app}, may be prefixed by "mp4:". You can override the value parsed from the URI through the @code{rtmp_playpath} option, too. +@item listen +Act as a server, listening for an incoming connection. + +@item timeout +Maximum time to wait for the incoming connection. Implies listen. @end table Additionally, the following parameters can be set via command line options diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index db1150186f..ca871c9cfa 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -29,6 +29,7 @@ #include "libavutil/intfloat.h" #include "libavutil/lfg.h" #include "libavutil/opt.h" +#include "libavutil/random_seed.h" #include "libavutil/sha.h" #include "avformat.h" #include "internal.h" @@ -51,6 +52,7 @@ #define PLAYPATH_MAX_LENGTH 256 #define TCURL_MAX_LENGTH 512 #define FLASHVER_MAX_LENGTH 64 +#define RTMP_PKTDATA_DEFAULT_SIZE 4096 /** RTMP protocol handler state */ typedef enum { @@ -59,6 +61,7 @@ typedef enum { STATE_FCPUBLISH, ///< client FCPublishing stream (for output) STATE_PLAYING, ///< client has started receiving multimedia data from server STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output) + STATE_RECEIVING, ///< received a publish command (for input) STATE_STOPPED, ///< the broadcast has been stopped } ClientState; @@ -110,6 +113,9 @@ typedef struct RTMPContext { TrackedMethod*tracked_methods; ///< tracked methods buffer int nb_tracked_methods; ///< number of tracked methods int tracked_methods_size; ///< size of the tracked methods buffer + int listen; ///< listen mode flag + int listen_timeout; ///< listen timeout to wait for new connections + int nb_streamid; ///< The next stream id to return on createStream calls } RTMPContext; #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing @@ -377,6 +383,151 @@ static int gen_connect(URLContext *s, RTMPContext *rt) return rtmp_send_packet(rt, &pkt, 1); } +static int read_connect(URLContext *s, RTMPContext *rt) +{ + RTMPPacket pkt = { 0 }; + uint8_t *p; + const uint8_t *cp; + int ret; + char command[64]; + int stringlen; + double seqnum; + uint8_t tmpstr[256]; + GetByteContext gbc; + + if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size, + rt->prev_pkt[1])) < 0) + return ret; + cp = pkt.data; + bytestream2_init(&gbc, cp, pkt.data_size); + if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) { + av_log(s, AV_LOG_ERROR, "Unable to read command string\n"); + ff_rtmp_packet_destroy(&pkt); + return AVERROR_INVALIDDATA; + } + if (strcmp(command, "connect")) { + av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command); + ff_rtmp_packet_destroy(&pkt); + return AVERROR_INVALIDDATA; + } + ret = ff_amf_read_number(&gbc, &seqnum); + if (ret) + av_log(s, AV_LOG_WARNING, "SeqNum not found\n"); + /* Here one could parse an AMF Object with data as flashVers and others. */ + ret = ff_amf_get_field_value(gbc.buffer, + gbc.buffer + bytestream2_get_bytes_left(&gbc), + "app", tmpstr, sizeof(tmpstr)); + if (ret) + av_log(s, AV_LOG_WARNING, "App field not found in connect\n"); + if (!ret && strcmp(tmpstr, rt->app)) + av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n", + tmpstr, rt->app); + ff_rtmp_packet_destroy(&pkt); + + // Send Window Acknowledgement Size (as defined in speficication) + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, + RTMP_PT_SERVER_BW, 0, 4)) < 0) + return ret; + p = pkt.data; + bytestream_put_be32(&p, rt->server_bw); + pkt.data_size = p - pkt.data; + ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&pkt); + if (ret < 0) + return ret; + // Send Peer Bandwidth + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, + RTMP_PT_CLIENT_BW, 0, 5)) < 0) + return ret; + p = pkt.data; + bytestream_put_be32(&p, rt->server_bw); + bytestream_put_byte(&p, 2); // dynamic + pkt.data_size = p - pkt.data; + ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&pkt); + if (ret < 0) + return ret; + + // Ping request + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, + RTMP_PT_PING, 0, 6)) < 0) + return ret; + + p = pkt.data; + bytestream_put_be16(&p, 0); // 0 -> Stream Begin + bytestream_put_be32(&p, 0); + ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&pkt); + if (ret < 0) + return ret; + + // Chunk size + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, + RTMP_PT_CHUNK_SIZE, 0, 4)) < 0) + return ret; + + p = pkt.data; + bytestream_put_be32(&p, rt->out_chunk_size); + ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&pkt); + if (ret < 0) + return ret; + + // Send result_ NetConnection.Connect.Success to connect + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, + RTMP_PT_INVOKE, 0, + RTMP_PKTDATA_DEFAULT_SIZE)) < 0) + return ret; + + p = pkt.data; + ff_amf_write_string(&p, "_result"); + ff_amf_write_number(&p, seqnum); + + ff_amf_write_object_start(&p); + ff_amf_write_field_name(&p, "fmsVer"); + ff_amf_write_string(&p, "FMS/3,0,1,123"); + ff_amf_write_field_name(&p, "capabilities"); + ff_amf_write_number(&p, 31); + ff_amf_write_object_end(&p); + + ff_amf_write_object_start(&p); + ff_amf_write_field_name(&p, "level"); + ff_amf_write_string(&p, "status"); + ff_amf_write_field_name(&p, "code"); + ff_amf_write_string(&p, "NetConnection.Connect.Success"); + ff_amf_write_field_name(&p, "description"); + ff_amf_write_string(&p, "Connection succeeded."); + ff_amf_write_field_name(&p, "objectEncoding"); + ff_amf_write_number(&p, 0); + ff_amf_write_object_end(&p); + + pkt.data_size = p - pkt.data; + ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&pkt); + if (ret < 0) + return ret; + + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, + RTMP_PT_INVOKE, 0, 30)) < 0) + return ret; + p = pkt.data; + ff_amf_write_string(&p, "onBWDone"); + ff_amf_write_number(&p, 0); + ff_amf_write_null(&p); + ff_amf_write_number(&p, 8192); + pkt.data_size = p - pkt.data; + ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&pkt); + + return ret; +} + /** * Generate 'releaseStream' call and send it to the server. It should make * the server release some channel for media streams. @@ -1138,6 +1289,123 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt) return 0; } +static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int, + uint32_t *second_int, char *arraydata, + int size) +{ + ssize_t inoutsize; + + inoutsize = ffurl_read_complete(rt->stream, arraydata, + RTMP_HANDSHAKE_PACKET_SIZE); + if (inoutsize <= 0) + return AVERROR(EIO); + if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) { + av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d" + " not following standard\n", (int)inoutsize); + return AVERROR(EINVAL); + } + + *first_int = AV_RB32(arraydata); + *second_int = AV_RB32(arraydata + 4); + return 0; +} + +static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int, + uint32_t second_int, char *arraydata, int size) +{ + ssize_t inoutsize; + + AV_WB32(arraydata, first_int); + AV_WB32(arraydata + 4, first_int); + inoutsize = ffurl_write(rt->stream, arraydata, + RTMP_HANDSHAKE_PACKET_SIZE); + if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) { + av_log(rt, AV_LOG_ERROR, "Unable to write answer\n"); + return AVERROR(EIO); + } + + return 0; +} + +/** + * rtmp handshake server side + */ +static int rtmp_server_handshake(URLContext *s, RTMPContext *rt) +{ + uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE]; + uint32_t hs_epoch; + uint32_t hs_my_epoch; + uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE]; + uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE]; + uint32_t zeroes; + uint32_t temp = 0; + int randomidx = 0; + ssize_t inoutsize = 0; + int ret; + + inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0 + if (inoutsize <= 0) { + av_log(s, AV_LOG_ERROR, "Unable to read handshake\n"); + return AVERROR(EIO); + } + // Check Version + if (buffer[0] != 3) { + av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n"); + return AVERROR(EIO); + } + if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0 + av_log(s, AV_LOG_ERROR, + "Unable to write answer - RTMP S0\n"); + return AVERROR(EIO); + } + /* Receive C1 */ + ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1, + RTMP_HANDSHAKE_PACKET_SIZE); + if (ret) { + av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n"); + return ret; + } + if (zeroes) + av_log(s, AV_LOG_WARNING, "Erroneous C1 Message zero != 0\n"); + /* Send S1 */ + /* By now same epoch will be sent */ + hs_my_epoch = hs_epoch; + /* Generate random */ + for (randomidx = 0; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE); + randomidx += 4) + AV_WB32(hs_s1 + 8 + randomidx, av_get_random_seed()); + + ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1, + RTMP_HANDSHAKE_PACKET_SIZE); + if (ret) { + av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n"); + return ret; + } + /* Send S2 */ + ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1, + RTMP_HANDSHAKE_PACKET_SIZE); + if (ret) { + av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n"); + return ret; + } + /* Receive C2 */ + ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer, + RTMP_HANDSHAKE_PACKET_SIZE); + if (ret) { + av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n"); + return ret; + } + if (temp != hs_my_epoch) + av_log(s, AV_LOG_WARNING, + "Erroneous C2 Message epoch does not match up with C1 epoch\n"); + if (memcmp(buffer + 8, hs_s1 + 8, + RTMP_HANDSHAKE_PACKET_SIZE - 8)) + av_log(s, AV_LOG_WARNING, + "Erroneous C2 Message random does not match up\n"); + + return 0; +} + static int handle_chunk_size(URLContext *s, RTMPPacket *pkt) { RTMPContext *rt = s->priv_data; @@ -1270,6 +1538,139 @@ static int handle_invoke_error(URLContext *s, RTMPPacket *pkt) return ret; } +static int send_invoke_response(URLContext *s, RTMPPacket *pkt) +{ + RTMPContext *rt = s->priv_data; + double seqnum; + char filename[64]; + char command[64]; + char statusmsg[128]; + int stringlen; + char *pchar; + const uint8_t *p = pkt->data; + uint8_t *pp = NULL; + RTMPPacket spkt = { 0 }; + GetByteContext gbc; + int ret; + + bytestream2_init(&gbc, p, pkt->data_size); + if (ff_amf_read_string(&gbc, command, sizeof(command), + &stringlen)) { + av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n"); + return AVERROR_INVALIDDATA; + } + + ret = ff_amf_read_number(&gbc, &seqnum); + if (ret) + return ret; + ret = ff_amf_read_null(&gbc); + if (ret) + return ret; + if (!strcmp(command, "FCPublish") || + !strcmp(command, "publish")) { + ret = ff_amf_read_string(&gbc, filename, + sizeof(filename), &stringlen); + // check with url + if (s->filename) { + pchar = strrchr(s->filename, '/'); + if (!pchar) { + av_log(s, AV_LOG_WARNING, + "Unable to find / in url %s, bad format\n", + s->filename); + pchar = s->filename; + } + pchar++; + if (strcmp(pchar, filename)) + av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting" + " %s\n", filename, pchar); + } + rt->state = STATE_RECEIVING; + } + + if (!strcmp(command, "FCPublish")) { + if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, + RTMP_PT_INVOKE, 0, + RTMP_PKTDATA_DEFAULT_SIZE)) < 0) { + av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); + return ret; + } + pp = spkt.data; + ff_amf_write_string(&pp, "onFCPublish"); + } else if (!strcmp(command, "publish")) { + PutByteContext pbc; + // Send Stream Begin 1 + if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL, + RTMP_PT_PING, 0, 6)) < 0) { + av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); + return ret; + } + pp = spkt.data; + bytestream2_init_writer(&pbc, pp, spkt.data_size); + bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin + bytestream2_put_be32(&pbc, rt->nb_streamid); + ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&spkt); + if (ret < 0) + return ret; + + // Send onStatus(NetStream.Publish.Start) + if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, + RTMP_PT_INVOKE, 0, + RTMP_PKTDATA_DEFAULT_SIZE)) < 0) { + av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); + return ret; + } + spkt.extra = pkt->extra; + pp = spkt.data; + ff_amf_write_string(&pp, "onStatus"); + ff_amf_write_number(&pp, 0); + ff_amf_write_null(&pp); + + ff_amf_write_object_start(&pp); + ff_amf_write_field_name(&pp, "level"); + ff_amf_write_string(&pp, "status"); + ff_amf_write_field_name(&pp, "code"); + ff_amf_write_string(&pp, "NetStream.Publish.Start"); + ff_amf_write_field_name(&pp, "description"); + snprintf(statusmsg, sizeof(statusmsg), + "%s is now published", filename); + ff_amf_write_string(&pp, statusmsg); + ff_amf_write_field_name(&pp, "details"); + ff_amf_write_string(&pp, filename); + ff_amf_write_field_name(&pp, "clientid"); + snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT); + ff_amf_write_string(&pp, statusmsg); + ff_amf_write_object_end(&pp); + + } else { + if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, + RTMP_PT_INVOKE, 0, + RTMP_PKTDATA_DEFAULT_SIZE)) < 0) { + av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); + return ret; + } + pp = spkt.data; + ff_amf_write_string(&pp, "_result"); + ff_amf_write_number(&pp, seqnum); + ff_amf_write_null(&pp); + if (!strcmp(command, "createStream")) { + rt->nb_streamid++; + if (rt->nb_streamid == 0 || rt->nb_streamid == 2) + rt->nb_streamid++; /* Values 0 and 2 are reserved */ + ff_amf_write_number(&pp, rt->nb_streamid); + /* By now we don't control which streams are removed in + * deleteStream. There is no stream creation control + * if a client creates more than 2^32 - 2 streams. */ + } + } + spkt.data_size = pp - spkt.data; + ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, + rt->prev_pkt[1]); + ff_rtmp_packet_destroy(&spkt); + return ret; +} + static int handle_invoke_result(URLContext *s, RTMPPacket *pkt) { RTMPContext *rt = s->priv_data; @@ -1384,11 +1785,79 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt) } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) { if ((ret = gen_check_bw(s, rt)) < 0) return ret; + } else if (!memcmp(pkt->data, "\002\000\015releaseStream", 16) || + !memcmp(pkt->data, "\002\000\011FCPublish", 12) || + !memcmp(pkt->data, "\002\000\007publish", 10) || + !memcmp(pkt->data, "\002\000\010_checkbw", 11) || + !memcmp(pkt->data, "\002\000\014createStream", 15)) { + if (ret = send_invoke_response(s, pkt) < 0) + return ret; } return ret; } +static int handle_notify(URLContext *s, RTMPPacket *pkt) { + RTMPContext *rt = s->priv_data; + const uint8_t *p = NULL; + uint8_t *cp = NULL; + uint8_t commandbuffer[64]; + char statusmsg[128]; + int stringlen; + GetByteContext gbc; + PutByteContext pbc; + uint32_t ts; + int old_flv_size; + const uint8_t *datatowrite; + unsigned datatowritelength; + + p = pkt->data; + bytestream2_init(&gbc, p, pkt->data_size); + if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer), + &stringlen)) + return AVERROR_INVALIDDATA; + if (!strcmp(commandbuffer, "@setDataFrame")) { + datatowrite = gbc.buffer; + datatowritelength = bytestream2_get_bytes_left(&gbc); + if (ff_amf_read_string(&gbc, statusmsg, + sizeof(statusmsg), &stringlen)) + return AVERROR_INVALIDDATA; + if (strcmp(statusmsg, "onMetaData")) { + av_log(s, AV_LOG_INFO, "Expecting onMetadata but got %s\n", + statusmsg); + return 0; + } + + /* Provide ECMAArray to flv */ + ts = pkt->timestamp; + + // generate packet header and put data into buffer for FLV demuxer + if (rt->flv_off < rt->flv_size) { + old_flv_size = rt->flv_size; + rt->flv_size += datatowritelength + 15; + } else { + old_flv_size = 0; + rt->flv_size = datatowritelength + 15; + rt->flv_off = 0; + } + + cp = av_realloc(rt->flv_data, rt->flv_size); + if (!cp) + return AVERROR(ENOMEM); + rt->flv_data = cp; + bytestream2_init_writer(&pbc, cp, rt->flv_size); + bytestream2_skip_p(&pbc, old_flv_size); + bytestream2_put_byte(&pbc, pkt->type); + bytestream2_put_be24(&pbc, datatowritelength); + bytestream2_put_be24(&pbc, ts); + bytestream2_put_byte(&pbc, ts >> 24); + bytestream2_put_be24(&pbc, 0); + bytestream2_put_buffer(&pbc, datatowrite, datatowritelength); + bytestream2_put_be32(&pbc, 0); + } + return 0; +} + /** * Parse received packet and possibly perform some action depending on * the packet contents. @@ -1430,6 +1899,7 @@ static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt) case RTMP_PT_VIDEO: case RTMP_PT_AUDIO: case RTMP_PT_METADATA: + case RTMP_PT_NOTIFY: /* Audio, Video and Metadata packets are parsed in get_packet() */ break; default: @@ -1489,7 +1959,9 @@ static int get_packet(URLContext *s, int for_header) ff_rtmp_packet_destroy(&rpkt); return AVERROR_EOF; } - if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) { + if (for_header && (rt->state == STATE_PLAYING || + rt->state == STATE_PUBLISHING || + rt->state == STATE_RECEIVING)) { ff_rtmp_packet_destroy(&rpkt); return 0; } @@ -1514,6 +1986,14 @@ static int get_packet(URLContext *s, int for_header) bytestream_put_be32(&p, 0); ff_rtmp_packet_destroy(&rpkt); return 0; + } else if (rpkt.type == RTMP_PT_NOTIFY) { + ret = handle_notify(s, &rpkt); + ff_rtmp_packet_destroy(&rpkt); + if (ret) { + av_log(s, AV_LOG_ERROR, "Handle notify error\n"); + return ret; + } + return 0; } else if (rpkt.type == RTMP_PT_METADATA) { // we got raw FLV data, make it available for FLV demuxer rt->flv_off = 0; @@ -1584,11 +2064,19 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) AVDictionary *opts = NULL; int ret; + if (rt->listen_timeout > 0) + rt->listen = 1; + rt->is_input = !(flags & AVIO_FLAG_WRITE); av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), s->filename); + if (rt->listen && strcmp(proto, "rtmp")) { + av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n", + proto); + return AVERROR(EINVAL); + } if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) { if (!strcmp(proto, "rtmpts")) av_dict_set(&opts, "ffrtmphttp_tls", "1", 1); @@ -1611,7 +2099,12 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) /* open the tcp connection */ if (port < 0) port = RTMP_DEFAULT_PORT; - ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); + if (rt->listen) + ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, + "?listen&listen_timeout=%d", + rt->listen_timeout * 1000); + else + ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); } if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE, @@ -1626,7 +2119,9 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) } rt->state = STATE_START; - if ((ret = rtmp_handshake(s, rt)) < 0) + if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0) + goto fail; + if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0) goto fail; rt->out_chunk_size = 128; @@ -1726,8 +2221,14 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n", proto, path, rt->app, rt->playpath); - if ((ret = gen_connect(s, rt)) < 0) - goto fail; + if (!rt->listen) { + if ((ret = gen_connect(s, rt)) < 0) + goto fail; + } else { + if (read_connect(s, s->priv_data) < 0) + goto fail; + rt->is_input = 1; + } do { ret = get_packet(s, 1); @@ -1919,6 +2420,8 @@ static const AVOption rtmp_options[] = { {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC}, {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, + {"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {-1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, { NULL }, }; diff --git a/libavformat/version.h b/libavformat/version.h index e54f22e7ab..1bc9ee76a1 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,8 +30,8 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 54 -#define LIBAVFORMAT_VERSION_MINOR 13 -#define LIBAVFORMAT_VERSION_MICRO 4 +#define LIBAVFORMAT_VERSION_MINOR 14 +#define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ From da8201cc82e379de6d756b993443fdd7e820869c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 16 Aug 2012 15:04:27 +0300 Subject: [PATCH 03/10] getopt: Add missing includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- compat/getopt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compat/getopt.c b/compat/getopt.c index 3a873b27ee..c7f8ef3260 100644 --- a/compat/getopt.c +++ b/compat/getopt.c @@ -30,6 +30,9 @@ * in the public domain. */ +#include +#include + #define EOF (-1) static int opterr = 1; From cb5ab02a88b3598acb23106ad3f140981ba56970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 16 Aug 2012 22:11:13 +0300 Subject: [PATCH 04/10] rtmp: Use int instead of ssize_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all compilers support ssize_t (MSVC doesn't), and none of these variables need to be larger than 32 bit. Signed-off-by: Martin Storsjö --- libavformat/rtmpproto.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index ca871c9cfa..6205cd2cb2 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -1293,7 +1293,7 @@ static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int, uint32_t *second_int, char *arraydata, int size) { - ssize_t inoutsize; + int inoutsize; inoutsize = ffurl_read_complete(rt->stream, arraydata, RTMP_HANDSHAKE_PACKET_SIZE); @@ -1313,7 +1313,7 @@ static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int, static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int, uint32_t second_int, char *arraydata, int size) { - ssize_t inoutsize; + int inoutsize; AV_WB32(arraydata, first_int); AV_WB32(arraydata + 4, first_int); @@ -1340,7 +1340,7 @@ static int rtmp_server_handshake(URLContext *s, RTMPContext *rt) uint32_t zeroes; uint32_t temp = 0; int randomidx = 0; - ssize_t inoutsize = 0; + int inoutsize = 0; int ret; inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0 From 962e912a496dd868055291a4e1e9902e6fb2b245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 16 Aug 2012 22:14:52 +0300 Subject: [PATCH 05/10] getopt: Remove an unnecessary define MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- compat/getopt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/compat/getopt.c b/compat/getopt.c index c7f8ef3260..3e7d3e215e 100644 --- a/compat/getopt.c +++ b/compat/getopt.c @@ -33,8 +33,6 @@ #include #include -#define EOF (-1) - static int opterr = 1; static int optind = 1; static int optopt; From 20bcce507aa6b9c866e34eee75d80305109767a8 Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Thu, 16 Aug 2012 00:10:33 +0100 Subject: [PATCH 06/10] configure: clean up Altivec detection There used to be one test for Altivec intrinsics support and a separate test to determine which of two possible syntaxes to use for vector literals. Since 2008, we only support the more common of these so the split test no longer makes sense. This combines the tests into one and also changes the hard error on failure to a warning. The test can reasonably fail if no --cpu flag is provided (or is provided with an unknown CPU) and the compiler default target does not support Altivec. Aborting in this case is probably over-reacting. Signed-off-by: Mans Rullgard --- configure | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 6622b24770..18f81e4d31 100755 --- a/configure +++ b/configure @@ -2875,17 +2875,14 @@ elif enabled ppc; then check_cc < Date: Thu, 16 Aug 2012 23:24:15 +0200 Subject: [PATCH 07/10] mjpegdec: more meaningful return values --- libavcodec/mjpegdec.c | 143 +++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 66 deletions(-) diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index c509402151..81aa36ab17 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -101,12 +101,13 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) build_basic_mjpeg_vlc(s); if (s->extern_huff) { + int ret; av_log(avctx, AV_LOG_INFO, "mjpeg: using external huffman table\n"); init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size * 8); - if (ff_mjpeg_decode_dht(s)) { + if ((ret = ff_mjpeg_decode_dht(s))) { av_log(avctx, AV_LOG_ERROR, "mjpeg: error using external huffman table\n"); - return AVERROR_INVALIDDATA; + return ret; } } if (avctx->field_order == AV_FIELD_BB) { /* quicktime icefloe 019 */ @@ -159,18 +160,19 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s) int len, index, i, class, n, v, code_max; uint8_t bits_table[17]; uint8_t val_table[256]; + int ret = 0; len = get_bits(&s->gb, 16) - 2; while (len > 0) { if (len < 17) - return -1; + return AVERROR_INVALIDDATA; class = get_bits(&s->gb, 4); if (class >= 2) - return -1; + return AVERROR_INVALIDDATA; index = get_bits(&s->gb, 4); if (index >= 4) - return -1; + return AVERROR_INVALIDDATA; n = 0; for (i = 1; i <= 16; i++) { bits_table[i] = get_bits(&s->gb, 8); @@ -178,7 +180,7 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s) } len -= 17; if (len < n || n > 256) - return -1; + return AVERROR_INVALIDDATA; code_max = 0; for (i = 0; i < n; i++) { @@ -193,15 +195,15 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s) ff_free_vlc(&s->vlcs[class][index]); av_log(s->avctx, AV_LOG_DEBUG, "class=%d index=%d nb_codes=%d\n", class, index, code_max + 1); - if (build_vlc(&s->vlcs[class][index], bits_table, val_table, - code_max + 1, 0, class > 0) < 0) - return -1; + if ((ret = build_vlc(&s->vlcs[class][index], bits_table, val_table, + code_max + 1, 0, class > 0)) < 0) + return ret; if (class > 0) { ff_free_vlc(&s->vlcs[2][index]); - if (build_vlc(&s->vlcs[2][index], bits_table, val_table, - code_max + 1, 0, 0) < 0) - return -1; + if ((ret = build_vlc(&s->vlcs[2][index], bits_table, val_table, + code_max + 1, 0, 0)) < 0) + return ret; } } return 0; @@ -234,16 +236,17 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) av_log(s->avctx, AV_LOG_DEBUG, "sof0: picture: %dx%d\n", width, height); if (av_image_check_size(width, height, 0, s->avctx)) - return -1; + return AVERROR_INVALIDDATA; nb_components = get_bits(&s->gb, 8); if (nb_components <= 0 || nb_components > MAX_COMPONENTS) return -1; if (s->ls && !(s->bits <= 8 || nb_components == 1)) { - av_log(s->avctx, AV_LOG_ERROR, - "only <= 8 bits/component or 16-bit gray accepted for JPEG-LS\n"); - return -1; + av_log_missing_feature(s->avctx, + "only <= 8 bits/component or " + "16-bit gray accepted for JPEG-LS\n", 0); + return AVERROR_PATCHWELCOME; } s->nb_components = nb_components; s->h_max = 1; @@ -260,16 +263,16 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) s->v_max = s->v_count[i]; s->quant_index[i] = get_bits(&s->gb, 8); if (s->quant_index[i] >= 4) - return -1; + return AVERROR_INVALIDDATA; av_log(s->avctx, AV_LOG_DEBUG, "component %d %d:%d id: %d quant:%d\n", i, s->h_count[i], s->v_count[i], s->component_id[i], s->quant_index[i]); } if (s->ls && (s->h_max > 1 || s->v_max > 1)) { - av_log(s->avctx, AV_LOG_ERROR, - "Subsampling in JPEG-LS is not supported.\n"); - return -1; + av_log_missing_feature(s->avctx, + "Subsampling in JPEG-LS is not supported.\n", 0); + return AVERROR_PATCHWELCOME; } if (s->v_max == 1 && s->h_max == 1 && s->lossless == 1) @@ -337,7 +340,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) break; default: av_log(s->avctx, AV_LOG_ERROR, "Unhandled pixel format 0x%x\n", pix_fmt_id); - return -1; + return AVERROR_PATCHWELCOME; } if (s->ls) { if (s->nb_components > 1) @@ -414,7 +417,7 @@ static int decode_block(MJpegDecodeContext *s, DCTELEM *block, int component, val = mjpeg_decode_dc(s, dc_index); if (val == 0xffff) { av_log(s->avctx, AV_LOG_ERROR, "error dc\n"); - return -1; + return AVERROR_INVALIDDATA; } val = val * quant_matrix[0] + s->last_dc[component]; s->last_dc[component] = val; @@ -442,7 +445,7 @@ static int decode_block(MJpegDecodeContext *s, DCTELEM *block, int component, if (i > 63) { av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i); - return -1; + return AVERROR_INVALIDDATA; } j = s->scantable.permutated[i]; block[j] = level * quant_matrix[j]; @@ -462,7 +465,7 @@ static int decode_dc_progressive(MJpegDecodeContext *s, DCTELEM *block, val = mjpeg_decode_dc(s, dc_index); if (val == 0xffff) { av_log(s->avctx, AV_LOG_ERROR, "error dc\n"); - return -1; + return AVERROR_INVALIDDATA; } val = (val * quant_matrix[0] << Al) + s->last_dc[component]; s->last_dc[component] = val; @@ -511,7 +514,7 @@ static int decode_block_progressive(MJpegDecodeContext *s, DCTELEM *block, break; } av_log(s->avctx, AV_LOG_ERROR, "error count: %d\n", i); - return -1; + return AVERROR_INVALIDDATA; } j = s->scantable.permutated[i]; block[j] = level * quant_matrix[j] << Al; @@ -520,7 +523,7 @@ static int decode_block_progressive(MJpegDecodeContext *s, DCTELEM *block, i += 15; if (i >= se) { av_log(s->avctx, AV_LOG_ERROR, "ZRL overflow: %d\n", i); - return -1; + return AVERROR_INVALIDDATA; } } else { val = (1 << run); @@ -840,7 +843,7 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, if (get_bits_left(&s->gb) < 0) { av_log(s->avctx, AV_LOG_ERROR, "overread %d\n", -get_bits_left(&s->gb)); - return -1; + return AVERROR_INVALIDDATA; } for (i = 0; i < nb_components; i++) { uint8_t *ptr; @@ -870,7 +873,7 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, s->quant_matrixes[s->quant_index[c]]) < 0) { av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); - return -1; + return AVERROR_INVALIDDATA; } s->dsp.idct_put(ptr, linesize[c], s->block); } @@ -886,7 +889,7 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah, Al) < 0) { av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); - return -1; + return AVERROR_INVALIDDATA; } } // av_log(s->avctx, AV_LOG_DEBUG, "mb: %d %d processed\n", @@ -971,7 +974,7 @@ static int mjpeg_decode_scan_progressive_ac(MJpegDecodeContext *s, int ss, if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "error y=%d x=%d\n", mb_y, mb_x); - return -1; + return AVERROR_INVALIDDATA; } } @@ -993,7 +996,7 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, const AVFrame *reference) { int len, nb_components, i, h, v, predictor, point_transform; - int index, id; + int index, id, ret; const int block_size = s->lossless ? 1 : 8; int ilv, prev_shift; @@ -1003,11 +1006,11 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, if (nb_components == 0 || nb_components > MAX_COMPONENTS) { av_log(s->avctx, AV_LOG_ERROR, "decode_sos: nb_components (%d) unsupported\n", nb_components); - return -1; + return AVERROR_PATCHWELCOME; } if (len != 6 + 2 * nb_components) { av_log(s->avctx, AV_LOG_ERROR, "decode_sos: invalid len (%d)\n", len); - return -1; + return AVERROR_INVALIDDATA; } for (i = 0; i < nb_components; i++) { id = get_bits(&s->gb, 8) - 1; @@ -1019,7 +1022,7 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, if (index == s->nb_components) { av_log(s->avctx, AV_LOG_ERROR, "decode_sos: index(%d) out of components\n", index); - return -1; + return AVERROR_INVALIDDATA; } /* Metasoft MJPEG codec has Cb and Cr swapped */ if (s->avctx->codec_tag == MKTAG('M', 'T', 'S', 'J') @@ -1081,40 +1084,46 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, // for () { // reset_ls_coding_parameters(s, 0); - if (ff_jpegls_decode_picture(s, predictor, point_transform, ilv) < 0) - return -1; + if ((ret = ff_jpegls_decode_picture(s, predictor, + point_transform, ilv)) < 0) + return ret; } else { if (s->rgb) { - if (ljpeg_decode_rgb_scan(s, predictor, point_transform) < 0) - return -1; + if ((ret = ljpeg_decode_rgb_scan(s, predictor, + point_transform)) < 0) + return ret; } else { - if (ljpeg_decode_yuv_scan(s, predictor, point_transform) < 0) - return -1; + if ((ret = ljpeg_decode_yuv_scan(s, predictor, + point_transform)) < 0) + return ret; } } } else { if (s->progressive && predictor) { - if (mjpeg_decode_scan_progressive_ac(s, predictor, ilv, prev_shift, - point_transform, - mb_bitmask, reference) < 0) - return -1; + if ((ret = mjpeg_decode_scan_progressive_ac(s, predictor, + ilv, prev_shift, + point_transform, + mb_bitmask, + reference)) < 0) + return ret; } else { - if (mjpeg_decode_scan(s, nb_components, prev_shift, point_transform, - mb_bitmask, reference) < 0) - return -1; + if ((ret = mjpeg_decode_scan(s, nb_components, + prev_shift, point_transform, + mb_bitmask, reference)) < 0) + return ret; } } emms_c(); return 0; out_of_range: av_log(s->avctx, AV_LOG_ERROR, "decode_sos: ac/dc index out of range\n"); - return -1; + return AVERROR_INVALIDDATA; } static int mjpeg_decode_dri(MJpegDecodeContext *s) { if (get_bits(&s->gb, 16) != 4) - return -1; + return AVERROR_INVALIDDATA; s->restart_interval = get_bits(&s->gb, 16); s->restart_count = 0; av_log(s->avctx, AV_LOG_DEBUG, "restart interval: %d\n", @@ -1129,9 +1138,9 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) len = get_bits(&s->gb, 16); if (len < 5) - return -1; + return AVERROR_INVALIDDATA; if (8 * len > get_bits_left(&s->gb)) - return -1; + return AVERROR_INVALIDDATA; id = get_bits_long(&s->gb, 32); id = av_be2ne32(id); @@ -1427,6 +1436,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *unescaped_buf_ptr; int unescaped_buf_size; int start_code; + int ret = 0; AVFrame *picture = data; s->got_picture = 0; // picture from previous image can not be reused @@ -1475,9 +1485,9 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_size, ff_mjpeg_decode_dqt(s); break; case DHT: - if (ff_mjpeg_decode_dht(s) < 0) { + if ((ret = ff_mjpeg_decode_dht(s)) < 0) { av_log(avctx, AV_LOG_ERROR, "huffman table decode error\n"); - return -1; + return ret; } break; case SOF0: @@ -1485,33 +1495,34 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_size, s->lossless = 0; s->ls = 0; s->progressive = 0; - if (ff_mjpeg_decode_sof(s) < 0) - return -1; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + return ret; break; case SOF2: s->lossless = 0; s->ls = 0; s->progressive = 1; - if (ff_mjpeg_decode_sof(s) < 0) - return -1; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + return ret; break; case SOF3: s->lossless = 1; s->ls = 0; s->progressive = 0; - if (ff_mjpeg_decode_sof(s) < 0) - return -1; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + return ret; break; case SOF48: s->lossless = 1; s->ls = 1; s->progressive = 0; - if (ff_mjpeg_decode_sof(s) < 0) - return -1; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + return ret; break; case LSE: - if (!CONFIG_JPEGLS_DECODER || ff_jpegls_decode_lse(s) < 0) - return -1; + if (!CONFIG_JPEGLS_DECODER || + (ret = ff_jpegls_decode_lse(s)) < 0) + return ret; break; case EOI: s->cur_scan = 0; @@ -1553,9 +1564,9 @@ eoi_parser: "Can not process SOS before SOF, skipping\n"); break; } - if (ff_mjpeg_decode_sos(s, NULL, NULL) < 0 && + if ((ret = ff_mjpeg_decode_sos(s, NULL, NULL)) < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) - return AVERROR_INVALIDDATA; + return ret; /* buggy avid puts EOI every 10-20th frame */ /* if restart period is over process EOI */ if ((s->buggy_avid && !s->interlaced) || s->restart_interval) @@ -1595,7 +1606,7 @@ not_the_end: goto eoi_parser; } av_log(avctx, AV_LOG_FATAL, "No JPEG data found in image\n"); - return -1; + return AVERROR_INVALIDDATA; the_end: av_log(avctx, AV_LOG_DEBUG, "mjpeg decode frame unused %td bytes\n", buf_end - buf_ptr); From fd6a085a22c540be88c46d277dce79c8b4b4c705 Mon Sep 17 00:00:00 2001 From: Jordi Ortiz Date: Wed, 15 Aug 2012 17:58:01 +0200 Subject: [PATCH 08/10] doc: Fix syntax errors in sample Emacs config Signed-off-by: Diego Biurrun --- doc/developer.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/developer.texi b/doc/developer.texi index 60f6d054da..ae9609dae6 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -235,8 +235,8 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}: (c-add-style "libav" '("k&r" (c-basic-offset . 4) - (indent-tabs-mode nil) - (show-trailing-whitespace t) + (indent-tabs-mode . nil) + (show-trailing-whitespace . t) (c-offsets-alist (statement-cont . (c-lineup-assignments +))) ) From 77f47e328800f5d7e7d1d3259a29c2eecc96daee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Ekstr=C3=B6m?= Date: Fri, 17 Aug 2012 13:33:52 +0300 Subject: [PATCH 09/10] utvideo: Rename utvideo.c to utvideodec.c Signed-off-by: Kostya Shishkov --- libavcodec/Makefile | 2 +- libavcodec/{utvideo.c => utvideodec.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename libavcodec/{utvideo.c => utvideodec.c} (100%) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index aaafa033d7..51a45bdeef 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -377,7 +377,7 @@ OBJS-$(CONFIG_TTA_DECODER) += tta.o OBJS-$(CONFIG_TWINVQ_DECODER) += twinvq.o celp_math.o OBJS-$(CONFIG_TXD_DECODER) += txd.o s3tc.o OBJS-$(CONFIG_ULTI_DECODER) += ulti.o -OBJS-$(CONFIG_UTVIDEO_DECODER) += utvideo.o +OBJS-$(CONFIG_UTVIDEO_DECODER) += utvideodec.o OBJS-$(CONFIG_V210_DECODER) += v210dec.o OBJS-$(CONFIG_V210_ENCODER) += v210enc.o OBJS-$(CONFIG_V410_DECODER) += v410dec.o diff --git a/libavcodec/utvideo.c b/libavcodec/utvideodec.c similarity index 100% rename from libavcodec/utvideo.c rename to libavcodec/utvideodec.c From 4aa3d7b3f2b71296d73276d62be4e806b34d2d01 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Thu, 16 Aug 2012 20:00:53 +0200 Subject: [PATCH 10/10] libvpxenc: use the default bitrate if not set Signed-off-by: Luca Barbato --- libavcodec/libvpxenc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index c5c522add2..3808ac02ec 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -245,11 +245,16 @@ static av_cold int vp8_init(AVCodecContext *avctx) else enccfg.g_pass = VPX_RC_ONE_PASS; + if (!avctx->bit_rate) + avctx->bit_rate = enccfg.rc_target_bitrate * 1000; + else + enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000, + AV_ROUND_NEAR_INF); + if (avctx->rc_min_rate == avctx->rc_max_rate && avctx->rc_min_rate == avctx->bit_rate) enccfg.rc_end_usage = VPX_CBR; - enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000, - AV_ROUND_NEAR_INF); + if (avctx->qmin > 0) enccfg.rc_min_quantizer = avctx->qmin; if (avctx->qmax > 0)