History

Merge remote-tracking branch 'qatar/master'

* qatar/master: librtmp: return AVERROR_UNKNOWN instead of -1. librtmp: don't abuse a variable for two unrelated things. librtmp: add rtmp_app and rtmp_playpath private options. bmv: add stricter checks for invalid decoded length avpacket: fix duplicating side data. flv: support stream text data as onTextData Conflicts: libavcodec/bmv.c libavformat/flvdec.c libavformat/flvenc.c

Michael Niedermayer committed 14 years ago

Commit 7d820202 parents e10eac9 19dfbf15 files · +252 −74Browse files

Unified · Split

5 files
  1. libavcodec/avpacket.c +1 −1
  2. libavcodec/bmv.c +8 −4
  3. libavformat/flvdec.c +92 −26
  4. libavformat/flvenc.c +60 −17
  5. libavformat/librtmp.c +91 −26
libavcodec/avpacket.c+1−1
@@ -152,7 +152,7 @@ int av_dup_packet(AVPacket *pkt) · 151 unmodified lines
152 pkt->side_data_elems * sizeof(*pkt->side_data));152 pkt->side_data_elems * sizeof(*pkt->side_data));
153 for (i = 0; i < pkt->side_data_elems; i++)153 for (i = 0; i < pkt->side_data_elems; i++)
154 DUP_DATA(pkt->side_data[i].data, tmp_pkt.side_data[i].data,154 DUP_DATA(pkt->side_data[i].data, tmp_pkt.side_data[i].data,
155 pkt->side_data[i].size, 1);155 tmp_pkt.side_data[i].size, 1);
156 }156 }
157 }157 }
158 return 0;158 return 0;
libavcodec/bmv.c+8−4
@@ -143,16 +143,20 @@ static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame, · 142 unmodified lines
143 switch (mode) {143 switch (mode) {
144 case 1:144 case 1:
145 if (forward) {145 if (forward) {
146 if (dst - frame + SCREEN_WIDE < -frame_off ||146 if (dst - frame + SCREEN_WIDE < frame_off ||
147 frame_end - dst < frame_off + len)147 dst - frame + SCREEN_WIDE + frame_off < 0 ||
148 frame_end - dst < frame_off + len ||
149 frame_end - dst < len)
148 return -1;150 return -1;
149 for (i = 0; i < len; i++)151 for (i = 0; i < len; i++)
150 dst[i] = dst[frame_off + i];152 dst[i] = dst[frame_off + i];
151 dst += len;153 dst += len;
152 } else {154 } else {
153 dst -= len;155 dst -= len;
154 if (dst - frame + SCREEN_WIDE < -frame_off ||156 if (dst - frame + SCREEN_WIDE < frame_off ||
155 frame_end - dst < frame_off + len)157 dst - frame + SCREEN_WIDE + frame_off < 0 ||
158 frame_end - dst < frame_off + len ||
159 frame_end - dst < len)
156 return -1;160 return -1;
157 for (i = len - 1; i >= 0; i--)161 for (i = len - 1; i >= 0; i--)
158 dst[i] = dst[frame_off + i];162 dst[i] = dst[frame_off + i];
libavformat/flvdec.c+92−26
@@ -62,6 +62,21 @@ static int flv_probe(AVProbeData *p) · 61 unmodified lines
62 return 0;62 return 0;
63}63}
64 64
65static AVStream *create_stream(AVFormatContext *s, int tag, int codec_type){
66 AVStream *st = avformat_new_stream(s, NULL);
67 if (!st)
68 return NULL;
69 st->id = tag;
70 st->codec->codec_type = codec_type;
71 if(s->nb_streams>=3 ||( s->nb_streams==2
72 && s->streams[0]->codec->codec_type != AVMEDIA_TYPE_DATA
73 && s->streams[1]->codec->codec_type != AVMEDIA_TYPE_DATA))
74 s->ctx_flags &= ~AVFMTCTX_NOHEADER;
75
76 avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
77 return st;
78}
79
65static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, AVCodecContext *acodec, int flv_codecid) {80static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, AVCodecContext *acodec, int flv_codecid) {
66 switch(flv_codecid) {81 switch(flv_codecid) {
67 //no distinction between S16 and S8 PCM codec flags82 //no distinction between S16 and S8 PCM codec flags
@@ -298,6 +313,12 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst · 230 unmodified lines
298 vcodec->bit_rate = num_val * 1024.0;313 vcodec->bit_rate = num_val * 1024.0;
299 else if (!strcmp(key, "audiodatarate") && acodec && 0 <= (int)(num_val * 1024.0))314 else if (!strcmp(key, "audiodatarate") && acodec && 0 <= (int)(num_val * 1024.0))
300 acodec->bit_rate = num_val * 1024.0;315 acodec->bit_rate = num_val * 1024.0;
316 else if (!strcmp(key, "datastream")) {
317 AVStream *st = create_stream(s, 2, AVMEDIA_TYPE_DATA);
318 if (!st)
319 return AVERROR(ENOMEM);
320 st->codec->codec_id = CODEC_ID_TEXT;
321 }
301 }322 }
302 323
303 if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&324 if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&
@@ -344,7 +365,14 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { · 40 unmodified lines
344 365
345 //first object needs to be "onMetaData" string366 //first object needs to be "onMetaData" string
346 type = avio_r8(ioc);367 type = avio_r8(ioc);
347 if(type != AMF_DATA_TYPE_STRING || amf_get_string(ioc, buffer, sizeof(buffer)) < 0 || strcmp(buffer, "onMetaData"))368 if (type != AMF_DATA_TYPE_STRING ||
369 amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
370 return -1;
371
372 if (!strcmp(buffer, "onTextData"))
373 return 1;
374
375 if (strcmp(buffer, "onMetaData"))
348 return -1;376 return -1;
349 377
350 //find the streams now so that amf_parse_object doesn't need to do the lookup every time it is called.378 //find the streams now so that amf_parse_object doesn't need to do the lookup every time it is called.
@@ -362,28 +390,6 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { · 11 unmodified lines
362 return 0;390 return 0;
363}391}
364 392
365static AVStream *create_stream(AVFormatContext *s, int stream_type){
366 AVStream *st = avformat_new_stream(s, NULL);
367 if (!st)
368 return NULL;
369 st->id = stream_type;
370 switch(stream_type) {
371 case FLV_STREAM_TYPE_VIDEO: st->codec->codec_type = AVMEDIA_TYPE_VIDEO; break;
372 case FLV_STREAM_TYPE_AUDIO: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; break;
373 case FLV_STREAM_TYPE_DATA:
374 st->codec->codec_type = AVMEDIA_TYPE_DATA;
375 st->codec->codec_id = CODEC_ID_NONE; // Going to rely on copy for now
376 av_log(s, AV_LOG_DEBUG, "Data stream created\n");
377 }
378 if(s->nb_streams>=3 ||( s->nb_streams==2
379 && s->streams[0]->codec->codec_type != AVMEDIA_TYPE_DATA
380 && s->streams[1]->codec->codec_type != AVMEDIA_TYPE_DATA))
381 s->ctx_flags &= ~AVFMTCTX_NOHEADER;
382
383 avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
384 return st;
385}
386
387static int flv_read_header(AVFormatContext *s)393static int flv_read_header(AVFormatContext *s)
388{394{
389 int offset, flags;395 int offset, flags;
@@ -399,11 +405,11 @@ static int flv_read_header(AVFormatContext *s) · 9 unmodified lines
399 s->ctx_flags |= AVFMTCTX_NOHEADER;405 s->ctx_flags |= AVFMTCTX_NOHEADER;
400 406
401 if(flags & FLV_HEADER_FLAG_HASVIDEO){407 if(flags & FLV_HEADER_FLAG_HASVIDEO){
402 if(!create_stream(s, FLV_STREAM_TYPE_VIDEO))408 if(!create_stream(s, 0, AVMEDIA_TYPE_VIDEO))
403 return AVERROR(ENOMEM);409 return AVERROR(ENOMEM);
404 }410 }
405 if(flags & FLV_HEADER_FLAG_HASAUDIO){411 if(flags & FLV_HEADER_FLAG_HASAUDIO){
406 if(!create_stream(s, FLV_STREAM_TYPE_AUDIO))412 if(!create_stream(s, 1, AVMEDIA_TYPE_AUDIO))
407 return AVERROR(ENOMEM);413 return AVERROR(ENOMEM);
408 }414 }
409 // Flag doesn't indicate whether or not there is script-data present. Must415 // Flag doesn't indicate whether or not there is script-data present. Must
@@ -466,6 +472,65 @@ static void clear_index_entries(AVFormatContext *s, int64_t pos) · 56 unmodified lines
466 }472 }
467}473}
468 474
475
476static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
477 int64_t dts, int64_t next)
478{
479 int ret = AVERROR_INVALIDDATA, i;
480 AVIOContext *pb = s->pb;
481 AVStream *st = NULL;
482 AMFDataType type;
483 char buf[20];
484 int length;
485
486 type = avio_r8(pb);
487 if (type == AMF_DATA_TYPE_MIXEDARRAY)
488 avio_seek(pb, 4, SEEK_CUR);
489 else if (type != AMF_DATA_TYPE_OBJECT)
490 goto out;
491
492 amf_get_string(pb, buf, sizeof(buf));
493 if (strcmp(buf, "type") || avio_r8(pb) != AMF_DATA_TYPE_STRING)
494 goto out;
495
496 amf_get_string(pb, buf, sizeof(buf));
497 //FIXME parse it as codec_id
498 amf_get_string(pb, buf, sizeof(buf));
499 if (strcmp(buf, "text") || avio_r8(pb) != AMF_DATA_TYPE_STRING)
500 goto out;
501
502 length = avio_rb16(pb);
503 ret = av_get_packet(s->pb, pkt, length);
504 if (ret < 0) {
505 ret = AVERROR(EIO);
506 goto out;
507 }
508
509 for (i = 0; i < s->nb_streams; i++) {
510 st = s->streams[i];
511 if (st->id == 2)
512 break;
513 }
514
515 if (i == s->nb_streams) {
516 st = create_stream(s, 2, AVMEDIA_TYPE_DATA);
517 if (!st)
518 goto out;
519 st->codec->codec_id = CODEC_ID_TEXT;
520 }
521
522 pkt->dts = dts;
523 pkt->pts = dts;
524 pkt->size = ret;
525
526 pkt->stream_index = st->index;
527 pkt->flags |= AV_PKT_FLAG_KEY;
528
529 avio_seek(s->pb, next + 4, SEEK_SET);
530out:
531 return ret;
532}
533
469static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)534static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
470{535{
471 FLVContext *flv = s->priv_data;536 FLVContext *flv = s->priv_data;
@@ -548,7 +613,8 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) · 76 unmodified lines
548 }613 }
549 if(i == s->nb_streams){614 if(i == s->nb_streams){
550 av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n");615 av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n");
551 st= create_stream(s, stream_type);616 st = create_stream(s, stream_type,
617 (int[]){AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA}[stream_type]);
552 }618 }
553 av_dlog(s, "%d %X %d \n", stream_type, flags, st->discard);619 av_dlog(s, "%d %X %d \n", stream_type, flags, st->discard);
554 if( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO)))620 if( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO)))
libavformat/flvenc.c+60−17
@@ -182,7 +182,7 @@ static int flv_write_header(AVFormatContext *s) · 181 unmodified lines
182{182{
183 AVIOContext *pb = s->pb;183 AVIOContext *pb = s->pb;
184 FLVContext *flv = s->priv_data;184 FLVContext *flv = s->priv_data;
185 AVCodecContext *audio_enc = NULL, *video_enc = NULL;185 AVCodecContext *audio_enc = NULL, *video_enc = NULL, *data_enc = NULL;
186 int i, metadata_count = 0;186 int i, metadata_count = 0;
187 double framerate = 0.0;187 double framerate = 0.0;
188 int64_t metadata_size_pos, data_size, metadata_count_pos;188 int64_t metadata_size_pos, data_size, metadata_count_pos;
@@ -191,7 +191,8 @@ static int flv_write_header(AVFormatContext *s) · 2 unmodified lines
191 for(i=0; i<s->nb_streams; i++){191 for(i=0; i<s->nb_streams; i++){
192 AVCodecContext *enc = s->streams[i]->codec;192 AVCodecContext *enc = s->streams[i]->codec;
193 FLVStreamContext *sc;193 FLVStreamContext *sc;
194 if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {194 switch (enc->codec_type) {
195 case AVMEDIA_TYPE_VIDEO:
195 if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) {196 if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) {
196 framerate = av_q2d(s->streams[i]->r_frame_rate);197 framerate = av_q2d(s->streams[i]->r_frame_rate);
197 } else {198 } else {
@@ -202,10 +203,22 @@ static int flv_write_header(AVFormatContext *s) · 4 unmodified lines
202 av_log(s, AV_LOG_ERROR, "video codec not compatible with flv\n");203 av_log(s, AV_LOG_ERROR, "video codec not compatible with flv\n");
203 return -1;204 return -1;
204 }205 }
205 } else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {206 break;
207 case AVMEDIA_TYPE_AUDIO:
206 audio_enc = enc;208 audio_enc = enc;
207 if (get_audio_flags(s, enc) < 0)209 if (get_audio_flags(s, enc) < 0)
208 return -1;210 return AVERROR_INVALIDDATA;
211 break;
212 case AVMEDIA_TYPE_DATA:
213 if (enc->codec_id != CODEC_ID_TEXT) {
214 av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n");
215 return AVERROR_INVALIDDATA;
216 }
217 data_enc = enc;
218 break;
219 default:
220 av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n");
221 return -1;
209 }222 }
210 avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */223 avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */
211 224
@@ -251,7 +264,11 @@ static int flv_write_header(AVFormatContext *s) · 39 unmodified lines
251 /* mixed array (hash) with size and string/type/data tuples */264 /* mixed array (hash) with size and string/type/data tuples */
252 avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);265 avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
253 metadata_count_pos = avio_tell(pb);266 metadata_count_pos = avio_tell(pb);
254 metadata_count = 5*!!video_enc + 5*!!audio_enc + 2; // +2 for duration and file size267 metadata_count = 5 * !!video_enc +
268 5 * !!audio_enc +
269 1 * !!data_enc +
270 2; // +2 for duration and file size
271
255 avio_wb32(pb, metadata_count);272 avio_wb32(pb, metadata_count);
256 273
257 put_amf_string(pb, "duration");274 put_amf_string(pb, "duration");
@@ -292,6 +309,11 @@ static int flv_write_header(AVFormatContext *s) · 34 unmodified lines
292 put_amf_double(pb, audio_enc->codec_tag);309 put_amf_double(pb, audio_enc->codec_tag);
293 }310 }
294 311
312 if (data_enc) {
313 put_amf_string(pb, "datastream");
314 put_amf_double(pb, 0.0);
315 }
316
295 while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {317 while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
296 if( !strcmp(tag->key, "width")318 if( !strcmp(tag->key, "width")
297 ||!strcmp(tag->key, "height")319 ||!strcmp(tag->key, "height")
@@ -416,7 +438,8 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) · 118 unmodified lines
416 else438 else
417 flags_size= 1;439 flags_size= 1;
418 440
419 if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {441 switch (enc->codec_type) {
442 case AVMEDIA_TYPE_VIDEO:
420 avio_w8(pb, FLV_TAG_TYPE_VIDEO);443 avio_w8(pb, FLV_TAG_TYPE_VIDEO);
421 444
422 flags = enc->codec_tag;445 flags = enc->codec_tag;
@@ -426,20 +449,20 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) · 3 unmodified lines
426 }449 }
427 450
428 flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER;451 flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER;
429 } else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {452 break;
453 case AVMEDIA_TYPE_AUDIO:
430 flags = get_audio_flags(s, enc);454 flags = get_audio_flags(s, enc);
431 455
432 assert(size);456 assert(size);
433 457
434 avio_w8(pb, FLV_TAG_TYPE_AUDIO);458 avio_w8(pb, FLV_TAG_TYPE_AUDIO);
435 } else {459 break;
436 // In-band flv metadata ("scriptdata")460 case AVMEDIA_TYPE_DATA:
437 assert(enc->codec_type == AVMEDIA_TYPE_DATA);
438 avio_w8(pb, FLV_TAG_TYPE_META);461 avio_w8(pb, FLV_TAG_TYPE_META);
439 flags_size = 0;462 break;
440 flags = 0;463 default:
464 return AVERROR(EINVAL);
441 }465 }
442
443 if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) {466 if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) {
444 /* check if extradata looks like mp4 formated */467 /* check if extradata looks like mp4 formated */
445 if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) {468 if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) {
@@ -476,9 +499,29 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) · 30 unmodified lines
476 avio_w8(pb,(ts >> 24) & 0x7F); // timestamps are 32bits _signed_499 avio_w8(pb,(ts >> 24) & 0x7F); // timestamps are 32bits _signed_
477 avio_wb24(pb,flv->reserved);500 avio_wb24(pb,flv->reserved);
478 501
479 if(flags_size)502 if (enc->codec_type == AVMEDIA_TYPE_DATA) {
480 avio_w8(pb,flags);503 int data_size;
481 504 int metadata_size_pos = avio_tell(pb);
505 avio_w8(pb, AMF_DATA_TYPE_STRING);
506 put_amf_string(pb, "onTextData");
507 avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
508 avio_wb32(pb, 2);
509 put_amf_string(pb, "type");
510 avio_w8(pb, AMF_DATA_TYPE_STRING);
511 put_amf_string(pb, "Text");
512 put_amf_string(pb, "text");
513 avio_w8(pb, AMF_DATA_TYPE_STRING);
514 put_amf_string(pb, pkt->data);
515 put_amf_string(pb, "");
516 avio_w8(pb, AMF_END_OF_OBJECT);
517 /* write total size of tag */
518 data_size = avio_tell(pb) - metadata_size_pos;
519 avio_seek(pb, metadata_size_pos - 10, SEEK_SET);
520 avio_wb24(pb, data_size);
521 avio_seek(pb, data_size + 10 - 3, SEEK_CUR);
522 avio_wb32(pb, data_size + 11);
523 } else {
524 avio_w8(pb,flags);
482 if (enc->codec_id == CODEC_ID_VP6)525 if (enc->codec_id == CODEC_ID_VP6)
483 avio_w8(pb,0);526 avio_w8(pb,0);
484 if (enc->codec_id == CODEC_ID_VP6F || enc->codec_id == CODEC_ID_VP6A)527 if (enc->codec_id == CODEC_ID_VP6F || enc->codec_id == CODEC_ID_VP6A)
@@ -494,7 +537,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) · 9 unmodified lines
494 537
495 avio_wb32(pb,size+flags_size+11); // previous tag size538 avio_wb32(pb,size+flags_size+11); // previous tag size
496 flv->duration = FFMAX(flv->duration, pkt->pts + flv->delay + pkt->duration);539 flv->duration = FFMAX(flv->duration, pkt->pts + flv->delay + pkt->duration);
497 540 }
498 avio_flush(pb);541 avio_flush(pb);
499 542
500 av_free(data);543 av_free(data);
libavformat/librtmp.c+91−26
@@ -24,13 +24,22 @@ · 23 unmodified lines
24 * RTMP protocol based on http://rtmpdump.mplayerhq.hu/ librtmp24 * RTMP protocol based on http://rtmpdump.mplayerhq.hu/ librtmp
25 */25 */
26 26
27#include "libavutil/avstring.h"
27#include "libavutil/mathematics.h"28#include "libavutil/mathematics.h"
29#include "libavutil/opt.h"
28#include "avformat.h"30#include "avformat.h"
29#include "url.h"31#include "url.h"
30 32
31#include <librtmp/rtmp.h>33#include <librtmp/rtmp.h>
32#include <librtmp/log.h>34#include <librtmp/log.h>
33 35
36typedef struct LibRTMPContext {
37 const AVClass *class;
38 RTMP rtmp;
39 char *app;
40 char *playpath;
41} LibRTMPContext;
42
34static void rtmp_log(int level, const char *fmt, va_list args)43static void rtmp_log(int level, const char *fmt, va_list args)
35{44{
36 switch (level) {45 switch (level) {
@@ -49,7 +58,8 @@ static void rtmp_log(int level, const char *fmt, va_list args) · 12 unmodified lines
49 58
50static int rtmp_close(URLContext *s)59static int rtmp_close(URLContext *s)
51{60{
52 RTMP *r = s->priv_data;61 LibRTMPContext *ctx = s->priv_data;
62 RTMP *r = &ctx->rtmp;
53 63
54 RTMP_Close(r);64 RTMP_Close(r);
55 return 0;65 return 0;
@@ -69,24 +79,45 @@ static int rtmp_close(URLContext *s) · 13 unmodified lines
69 */79 */
70static int rtmp_open(URLContext *s, const char *uri, int flags)80static int rtmp_open(URLContext *s, const char *uri, int flags)
71{81{
72 RTMP *r = s->priv_data;82 LibRTMPContext *ctx = s->priv_data;
73 int rc;83 RTMP *r = &ctx->rtmp;
84 int rc = 0, level;
85 char *filename = s->filename;
74 86
75 switch (av_log_get_level()) {87 switch (av_log_get_level()) {
76 default:88 default:
77 case AV_LOG_FATAL: rc = RTMP_LOGCRIT; break;89 case AV_LOG_FATAL: level = RTMP_LOGCRIT; break;
78 case AV_LOG_ERROR: rc = RTMP_LOGERROR; break;90 case AV_LOG_ERROR: level = RTMP_LOGERROR; break;
79 case AV_LOG_WARNING: rc = RTMP_LOGWARNING; break;91 case AV_LOG_WARNING: level = RTMP_LOGWARNING; break;
80 case AV_LOG_INFO: rc = RTMP_LOGINFO; break;92 case AV_LOG_INFO: level = RTMP_LOGINFO; break;
81 case AV_LOG_VERBOSE: rc = RTMP_LOGDEBUG; break;93 case AV_LOG_VERBOSE: level = RTMP_LOGDEBUG; break;
82 case AV_LOG_DEBUG: rc = RTMP_LOGDEBUG2; break;94 case AV_LOG_DEBUG: level = RTMP_LOGDEBUG2; break;
83 }95 }
84 RTMP_LogSetLevel(rc);96 RTMP_LogSetLevel(level);
85 RTMP_LogSetCallback(rtmp_log);97 RTMP_LogSetCallback(rtmp_log);
86 98
99 if (ctx->app || ctx->playpath) {
100 int len = strlen(s->filename) + 1;
101 if (ctx->app) len += strlen(ctx->app) + sizeof(" app=");
102 if (ctx->playpath) len += strlen(ctx->playpath) + sizeof(" playpath=");
103
104 if (!(filename = av_malloc(len)))
105 return AVERROR(ENOMEM);
106
107 av_strlcpy(filename, s->filename, len);
108 if (ctx->app) {
109 av_strlcat(filename, " app=", len);
110 av_strlcat(filename, ctx->app, len);
111 }
112 if (ctx->playpath) {
113 av_strlcat(filename, " playpath=", len);
114 av_strlcat(filename, ctx->playpath, len);
115 }
116 }
117
87 RTMP_Init(r);118 RTMP_Init(r);
88 if (!RTMP_SetupURL(r, s->filename)) {119 if (!RTMP_SetupURL(r, filename)) {
89 rc = -1;120 rc = AVERROR_UNKNOWN;
90 goto fail;121 goto fail;
91 }122 }
92 123
@@ -94,43 +125,49 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) · 1 unmodified line
94 RTMP_EnableWrite(r);125 RTMP_EnableWrite(r);
95 126
96 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0)) {127 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0)) {
97 rc = -1;128 rc = AVERROR_UNKNOWN;
98 goto fail;129 goto fail;
99 }130 }
100 131
101 s->is_streamed = 1;132 s->is_streamed = 1;
102 return 0;133 rc = 0;
103fail:134fail:
135 if (filename != s->filename)
136 av_freep(&filename);
104 return rc;137 return rc;
105}138}
106 139
107static int rtmp_write(URLContext *s, const uint8_t *buf, int size)140static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
108{141{
109 RTMP *r = s->priv_data;142 LibRTMPContext *ctx = s->priv_data;
143 RTMP *r = &ctx->rtmp;
110 144
111 return RTMP_Write(r, buf, size);145 return RTMP_Write(r, buf, size);
112}146}
113 147
114static int rtmp_read(URLContext *s, uint8_t *buf, int size)148static int rtmp_read(URLContext *s, uint8_t *buf, int size)
115{149{
116 RTMP *r = s->priv_data;150 LibRTMPContext *ctx = s->priv_data;
151 RTMP *r = &ctx->rtmp;
117 152
118 return RTMP_Read(r, buf, size);153 return RTMP_Read(r, buf, size);
119}154}
120 155
121static int rtmp_read_pause(URLContext *s, int pause)156static int rtmp_read_pause(URLContext *s, int pause)
122{157{
123 RTMP *r = s->priv_data;158 LibRTMPContext *ctx = s->priv_data;
159 RTMP *r = &ctx->rtmp;
124 160
125 if (!RTMP_Pause(r, pause))161 if (!RTMP_Pause(r, pause))
126 return -1;162 return AVERROR_UNKNOWN;
127 return 0;163 return 0;
128}164}
129 165
130static int64_t rtmp_read_seek(URLContext *s, int stream_index,166static int64_t rtmp_read_seek(URLContext *s, int stream_index,
131 int64_t timestamp, int flags)167 int64_t timestamp, int flags)
132{168{
133 RTMP *r = s->priv_data;169 LibRTMPContext *ctx = s->priv_data;
170 RTMP *r = &ctx->rtmp;
134 171
135 if (flags & AVSEEK_FLAG_BYTE)172 if (flags & AVSEEK_FLAG_BYTE)
136 return AVERROR(ENOSYS);173 return AVERROR(ENOSYS);
@@ -141,17 +178,36 @@ static int64_t rtmp_read_seek(URLContext *s, int stream_index, · 4 unmodified lines
141 flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP);178 flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP);
142 179
143 if (!RTMP_SendSeek(r, timestamp))180 if (!RTMP_SendSeek(r, timestamp))
144 return -1;181 return AVERROR_UNKNOWN;
145 return timestamp;182 return timestamp;
146}183}
147 184
148static int rtmp_get_file_handle(URLContext *s)185static int rtmp_get_file_handle(URLContext *s)
149{186{
150 RTMP *r = s->priv_data;187 LibRTMPContext *ctx = s->priv_data;
188 RTMP *r = &ctx->rtmp;
151 189
152 return RTMP_Socket(r);190 return RTMP_Socket(r);
153}191}
154 192
193#define OFFSET(x) offsetof(LibRTMPContext, x)
194#define DEC AV_OPT_FLAG_DECODING_PARAM
195#define ENC AV_OPT_FLAG_ENCODING_PARAM
196static const AVOption options[] = {
197 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
198 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
199 { NULL },
200};
201
202#define RTMP_CLASS(flavor)\
203static const AVClass lib ## flavor ## _class = {\
204 .class_name = "lib" #flavor " protocol",\
205 .item_name = av_default_item_name,\
206 .option = options,\
207 .version = LIBAVUTIL_VERSION_INT,\
208};
209
210RTMP_CLASS(rtmp)
155URLProtocol ff_librtmp_protocol = {211URLProtocol ff_librtmp_protocol = {
156 .name = "rtmp",212 .name = "rtmp",
157 .url_open = rtmp_open,213 .url_open = rtmp_open,
@@ -161,10 +217,12 @@ URLProtocol ff_librtmp_protocol = { · 3 unmodified lines
161 .url_read_pause = rtmp_read_pause,217 .url_read_pause = rtmp_read_pause,
162 .url_read_seek = rtmp_read_seek,218 .url_read_seek = rtmp_read_seek,
163 .url_get_file_handle = rtmp_get_file_handle,219 .url_get_file_handle = rtmp_get_file_handle,
164 .priv_data_size = sizeof(RTMP),220 .priv_data_size = sizeof(LibRTMPContext),
221 .priv_data_class = &librtmp_class,
165 .flags = URL_PROTOCOL_FLAG_NETWORK,222 .flags = URL_PROTOCOL_FLAG_NETWORK,
166};223};
167 224
225RTMP_CLASS(rtmpt)
168URLProtocol ff_librtmpt_protocol = {226URLProtocol ff_librtmpt_protocol = {
169 .name = "rtmpt",227 .name = "rtmpt",
170 .url_open = rtmp_open,228 .url_open = rtmp_open,
@@ -174,10 +232,12 @@ URLProtocol ff_librtmpt_protocol = { · 3 unmodified lines
174 .url_read_pause = rtmp_read_pause,232 .url_read_pause = rtmp_read_pause,
175 .url_read_seek = rtmp_read_seek,233 .url_read_seek = rtmp_read_seek,
176 .url_get_file_handle = rtmp_get_file_handle,234 .url_get_file_handle = rtmp_get_file_handle,
177 .priv_data_size = sizeof(RTMP),235 .priv_data_size = sizeof(LibRTMPContext),
236 .priv_data_class = &librtmpt_class,
178 .flags = URL_PROTOCOL_FLAG_NETWORK,237 .flags = URL_PROTOCOL_FLAG_NETWORK,
179};238};
180 239
240RTMP_CLASS(rtmpe)
181URLProtocol ff_librtmpe_protocol = {241URLProtocol ff_librtmpe_protocol = {
182 .name = "rtmpe",242 .name = "rtmpe",
183 .url_open = rtmp_open,243 .url_open = rtmp_open,
@@ -187,10 +247,12 @@ URLProtocol ff_librtmpe_protocol = { · 3 unmodified lines
187 .url_read_pause = rtmp_read_pause,247 .url_read_pause = rtmp_read_pause,
188 .url_read_seek = rtmp_read_seek,248 .url_read_seek = rtmp_read_seek,
189 .url_get_file_handle = rtmp_get_file_handle,249 .url_get_file_handle = rtmp_get_file_handle,
190 .priv_data_size = sizeof(RTMP),250 .priv_data_size = sizeof(LibRTMPContext),
251 .priv_data_class = &librtmpe_class,
191 .flags = URL_PROTOCOL_FLAG_NETWORK,252 .flags = URL_PROTOCOL_FLAG_NETWORK,
192};253};
193 254
255RTMP_CLASS(rtmpte)
194URLProtocol ff_librtmpte_protocol = {256URLProtocol ff_librtmpte_protocol = {
195 .name = "rtmpte",257 .name = "rtmpte",
196 .url_open = rtmp_open,258 .url_open = rtmp_open,
@@ -200,10 +262,12 @@ URLProtocol ff_librtmpte_protocol = { · 3 unmodified lines
200 .url_read_pause = rtmp_read_pause,262 .url_read_pause = rtmp_read_pause,
201 .url_read_seek = rtmp_read_seek,263 .url_read_seek = rtmp_read_seek,
202 .url_get_file_handle = rtmp_get_file_handle,264 .url_get_file_handle = rtmp_get_file_handle,
203 .priv_data_size = sizeof(RTMP),265 .priv_data_size = sizeof(LibRTMPContext),
266 .priv_data_class = &librtmpte_class,
204 .flags = URL_PROTOCOL_FLAG_NETWORK,267 .flags = URL_PROTOCOL_FLAG_NETWORK,
205};268};
206 269
270RTMP_CLASS(rtmps)
207URLProtocol ff_librtmps_protocol = {271URLProtocol ff_librtmps_protocol = {
208 .name = "rtmps",272 .name = "rtmps",
209 .url_open = rtmp_open,273 .url_open = rtmp_open,
@@ -213,6 +277,7 @@ URLProtocol ff_librtmps_protocol = { · 3 unmodified lines
213 .url_read_pause = rtmp_read_pause,277 .url_read_pause = rtmp_read_pause,
214 .url_read_seek = rtmp_read_seek,278 .url_read_seek = rtmp_read_seek,
215 .url_get_file_handle = rtmp_get_file_handle,279 .url_get_file_handle = rtmp_get_file_handle,
216 .priv_data_size = sizeof(RTMP),280 .priv_data_size = sizeof(LibRTMPContext),
281 .priv_data_class = &librtmps_class,
217 .flags = URL_PROTOCOL_FLAG_NETWORK,282 .flags = URL_PROTOCOL_FLAG_NETWORK,
218};283};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t