[FFmpeg-devel] MPEG Video support in RTP
Claudio Bertozzi
becl75
Fri Aug 24 17:44:27 CEST 2007
hi and first of all sorry if this is not the appropriate place to post
my question,
I'm reading this mailing list for a while and now I'm trying to use
libavcodec & libavformat library in my code, but without any
documentation and without any previous experience in that work it is
not simple. Anyway, following some examples, now I'm able to take
frames from my source, coding in MPEG1/2 format and writing them into
a well format .mpg video file. Now I want to stream every single
encoded frame via RTP instead to save it in a file, without using
other library such as LIVE555.
I read in this topic that you are working (in the same good way) in
that direction to provide function to do that. Could I ask you where I
can find some example to learn how to stream through RTP using this
libavformat library? (example or documentation or some sort of help or
topic in any forum...I searched but I didn't find out anything
useful).
thanks in advance for any help you could give and also for the very
good works on this project.
Claudio
2007/8/24, Luca Abeni <lucabe72 at email.it>:
> Hi,
>
> Luca Abeni wrote:
> > Hi Luca,
> >
> > Luca Barbato wrote:
> > [...]
> >>> ops... Sorry, I've been too fast in sending the patch. I updated my
> >>> local copy with the headers from rtp.{c,h}
> >>>
> >> If is still working as supposed please commit =)
> >
> > Ok, thanks. I'll wait one day or two to give other people the
> > possibility to comment, and then I'll commit.
>
> Ok, committed. Now, here are the interesting patches:
>
> - remove_header_extension.diff: the current code writes an empty payload
> header extension if the video is MPEG2. However, this header is wrong
> (filled with all 0s), and according to the standard "its inclusion in an
> RTP packet is optional". Since removing this header we are still
> compliant with RFC2250 (even in case of MPEG2 video), this patch is
> removing it.
>
> - fix_packetization.diff: this is the biggest patch. It ensures that a
> video frame is correctly split on frame boundaries, according to
> RFC2250. Note: the patch assumes that video sequence header, gop header,
> and picture header if present are at the beginning of a frame (I think
> this is guaranteed by the MPEG standard, right?), and that the first
> packet is big enough to contain such headers.
> After applying this patch, the payload header is still wrong, but the
> frame should be correctly packetized, and we have all the information
> needed to fill the header. The patch is more complex than I would have
> liked, but I've not been able to come out with something simpler than
> this... Suggestions are welcome.
>
> - set_bs_es.diff: trivial patch to correctly set the B (beginning of
> slice) and E (end of slice) bits in the payload header. After applying
> this, vlc is happy with the video streamed by ffmpeg!
>
> - set_frame_type.diff: set the P field in the payload header. Note: in
> the patch, I assume that the frame is well-formed (I consider writing a
> non-well-formed frame similar to setting a wrong "size" field in
> AVPacket). Is this reasonable? If not, I'll add a check when reading
> frame_type
>
> - set_tr.diff: set the TR field in the payload header
>
> - set_begin_of_sequence.diff: set the B flag in the payload header
>
> Note that I do not know about clients using the P, TR, and B fields...
> So I just checked them with wireshark, and after my patches they look
> reasonable. I still need to write the FBV, BFC, FFV, and FFC flags... If
> noone does this before, I will work on them next week (I need to find
> how to compute those fields based on the MPEG standard.
>
>
> Thanks,
> Luca
>
> Index: ffmpeg/libavformat/rtp_mpv.c
> ===================================================================
> --- ffmpeg.orig/libavformat/rtp_mpv.c 2007-08-22 16:00:59.000000000 +0200
> +++ ffmpeg/libavformat/rtp_mpv.c 2007-08-22 16:25:28.000000000 +0200
> @@ -35,22 +35,12 @@
> while (size > 0) {
> /* XXX: more correct headers */
> h = 0;
> - if (st->codec->sub_id == 2)
> - h |= 1 << 26; /* mpeg 2 indicator */
> q = s->buf;
> *q++ = h >> 24;
> *q++ = h >> 16;
> *q++ = h >> 8;
> *q++ = h;
>
> - if (st->codec->sub_id == 2) {
> - h = 0;
> - *q++ = h >> 24;
> - *q++ = h >> 16;
> - *q++ = h >> 8;
> - *q++ = h;
> - }
> -
> len = max_packet_size - (q - s->buf);
> if (len > size)
> len = size;
>
> Index: ffmpeg/libavformat/rtp_mpv.c
> ===================================================================
> --- ffmpeg.orig/libavformat/rtp_mpv.c 2007-08-22 16:26:25.000000000 +0200
> +++ ffmpeg/libavformat/rtp_mpv.c 2007-08-22 16:34:03.000000000 +0200
> @@ -21,6 +21,8 @@
> #include "avformat.h"
> #include "rtp_internal.h"
>
> +#include "mpegvideo.h"
> +
> /* NOTE: a single frame must be passed with sequence header if
> needed. XXX: use slices. */
> void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size)
> @@ -29,22 +31,53 @@
> AVStream *st = s1->streams[0];
> int len, h, max_packet_size;
> uint8_t *q;
> + int begin_of_slice, end_of_slice;
>
> - max_packet_size = s->max_payload_size;
> + max_packet_size = s->max_payload_size - 4; /* 4 bytes for the payload header */
> + begin_of_slice = 1;
> + end_of_slice = 0;
>
> while (size > 0) {
> /* XXX: more correct headers */
> h = 0;
> q = s->buf;
> + len = FFMIN(max_packet_size - (q - s->buf), size);
> + if (len == size) {
> + end_of_slice = 1;
> + } else {
> + const uint8_t *r, *r1;
> + int start_code, done;
> +
> + r1 = buf1;
> + done = 0;
> + while (!done) {
> + start_code = -1;
> + r = ff_find_start_code(r1, buf1 + size, &start_code);
> + if((start_code & 0xFFFFFF00) == 0x100) {
> + /* New start code found */
> + if (r - buf1 - 4 < len) {
> + /* The current slice fits in the packet */
> + if (begin_of_slice == 0) {
> + /* no slice at the beginning of the packet... */
> + done = 1;
> + end_of_slice = 1;
> + len = r1 - buf1 - 4;
> + }
> + r1 = r;
> + } else {
> + done = 1;
> + }
> + } else {
> + done = 1;
> + }
> + }
> + }
> +
> *q++ = h >> 24;
> *q++ = h >> 16;
> *q++ = h >> 8;
> *q++ = h;
>
> - len = max_packet_size - (q - s->buf);
> - if (len > size)
> - len = size;
> -
> memcpy(q, buf1, len);
> q += len;
>
> @@ -55,6 +88,8 @@
>
> buf1 += len;
> size -= len;
> + begin_of_slice = end_of_slice;
> + end_of_slice = 0;
> }
> s->cur_timestamp++;
> }
>
> Index: ffmpeg/libavformat/rtp_mpv.c
> ===================================================================
> --- ffmpeg.orig/libavformat/rtp_mpv.c 2007-08-22 16:35:16.000000000 +0200
> +++ ffmpeg/libavformat/rtp_mpv.c 2007-08-22 16:52:49.000000000 +0200
> @@ -73,6 +73,8 @@
> }
> }
>
> + h |= begin_of_slice << 12;
> + h |= end_of_slice << 11;
> *q++ = h >> 24;
> *q++ = h >> 16;
> *q++ = h >> 8;
>
> Index: ffmpeg/libavformat/rtp_mpv.c
> ===================================================================
> --- ffmpeg.orig/libavformat/rtp_mpv.c 2007-08-22 16:37:37.000000000 +0200
> +++ ffmpeg/libavformat/rtp_mpv.c 2007-08-22 16:39:26.000000000 +0200
> @@ -31,11 +31,12 @@
> AVStream *st = s1->streams[0];
> int len, h, max_packet_size;
> uint8_t *q;
> - int begin_of_slice, end_of_slice;
> + int begin_of_slice, end_of_slice, frame_type;
>
> max_packet_size = s->max_payload_size - 4; /* 4 bytes for the payload header */
> begin_of_slice = 1;
> end_of_slice = 0;
> + frame_type = 0;
>
> while (size > 0) {
> /* XXX: more correct headers */
> @@ -55,6 +56,10 @@
> r = ff_find_start_code(r1, buf1 + size, &start_code);
> if((start_code & 0xFFFFFF00) == 0x100) {
> /* New start code found */
> + if (start_code == 0x100) {
> + frame_type = (r[1] & 0x38) >> 3;
> + }
> +
> if (r - buf1 - 4 < len) {
> /* The current slice fits in the packet */
> if (begin_of_slice == 0) {
> @@ -75,6 +80,7 @@
>
> h |= begin_of_slice << 12;
> h |= end_of_slice << 11;
> + h |= frame_type << 8;
> *q++ = h >> 24;
> *q++ = h >> 16;
> *q++ = h >> 8;
>
> Index: ffmpeg/libavformat/rtp_mpv.c
> ===================================================================
> --- ffmpeg.orig/libavformat/rtp_mpv.c 2007-08-22 16:40:39.000000000 +0200
> +++ ffmpeg/libavformat/rtp_mpv.c 2007-08-22 16:42:42.000000000 +0200
> @@ -31,11 +31,12 @@
> AVStream *st = s1->streams[0];
> int len, h, max_packet_size;
> uint8_t *q;
> - int begin_of_slice, end_of_slice, frame_type;
> + int begin_of_slice, end_of_slice, temporal_reference, frame_type;
>
> max_packet_size = s->max_payload_size - 4; /* 4 bytes for the payload header */
> begin_of_slice = 1;
> end_of_slice = 0;
> + temporal_reference = 0;
> frame_type = 0;
>
> while (size > 0) {
> @@ -57,6 +58,7 @@
> if((start_code & 0xFFFFFF00) == 0x100) {
> /* New start code found */
> if (start_code == 0x100) {
> + temporal_reference = (int)r[0] << 2 | r[1] >> 6;
> frame_type = (r[1] & 0x38) >> 3;
> }
>
> @@ -78,6 +80,7 @@
> }
> }
>
> + h |= temporal_reference << 16;
> h |= begin_of_slice << 12;
> h |= end_of_slice << 11;
> h |= frame_type << 8;
>
> Index: ffmpeg/libavformat/rtp_mpv.c
> ===================================================================
> --- ffmpeg.orig/libavformat/rtp_mpv.c 2007-08-22 16:55:40.000000000 +0200
> +++ ffmpeg/libavformat/rtp_mpv.c 2007-08-22 16:56:13.000000000 +0200
> @@ -40,9 +40,12 @@
> frame_type = 0;
>
> while (size > 0) {
> + int begin_of_sequence;
> +
> /* XXX: more correct headers */
> h = 0;
> q = s->buf;
> + begin_of_sequence = 0;
> len = FFMIN(max_packet_size - (q - s->buf), size);
> if (len == size) {
> end_of_slice = 1;
> @@ -57,6 +60,9 @@
> r = ff_find_start_code(r1, buf1 + size, &start_code);
> if((start_code & 0xFFFFFF00) == 0x100) {
> /* New start code found */
> + if (start_code == 0x1B8) {
> + begin_of_sequence = 1;
> + }
> if (start_code == 0x100) {
> temporal_reference = (int)r[0] << 2 | r[1] >> 6;
> frame_type = (r[1] & 0x38) >> 3;
> @@ -81,6 +87,7 @@
> }
>
> h |= temporal_reference << 16;
> + h |= begin_of_sequence << 13;
> h |= begin_of_slice << 12;
> h |= end_of_slice << 11;
> h |= frame_type << 8;
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at mplayerhq.hu
> http://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-devel
>
More information about the ffmpeg-devel
mailing list