[FFmpeg-devel] [PATCH 5/6] RTMP output: implement rtmp-output

Kostya kostya.shishkov
Thu Dec 3 17:32:51 CET 2009


On Thu, Dec 03, 2009 at 05:15:08PM +0200, Sergiy wrote:
> Also for handshake with red5, 1st part of server response, received by
> client must be sent back.

[...]
> @@ -163,20 +195,28 @@ static void gen_play(URLContext *s, RTMPContext *rt)
>      RTMPPacket pkt;
>      uint8_t *p;
>  
> -    av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
> -    ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
> -                          20 + strlen(rt->playpath));
> +    av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending %s command for '%s'\n", rt->is_input ? "play" : "publish",
> +           rt->playpath);
> +    ff_rtmp_packet_create(&pkt, rt->is_input ? RTMP_VIDEO_CHANNEL : RTMP_SOURCE_CHANNEL,
> +                          RTMP_PT_INVOKE, 0, 4096);
>      pkt.extra = rt->main_channel_id;
>  
>      p = pkt.data;
> +    if (rt->is_input)
>      ff_amf_write_string(&p, "play");
> +    else
> +        ff_amf_write_string(&p, "publish");
>      ff_amf_write_number(&p, 0.0);
>      ff_amf_write_null(&p);
>      ff_amf_write_string(&p, rt->playpath);
> +    if (!rt->is_input)
> +        ff_amf_write_string(&p, "live");
> +    pkt.data_size = p - pkt.data;
>  
>      ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
>      ff_rtmp_packet_destroy(&pkt);
>  
> +    if (rt->is_input) {
>      // set client buffer time disguised in ping packet
>      ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);

Ahem, sending "publish" instead of "play" in gen_play() is a bit
counterintuitive, don't you think? Make it a separate function instead.

[...]
>  
>  static int rtmp_write(URLContext *h, uint8_t *buf, int size)
>  {
> -    return 0;
> +    RTMPContext *rt = h->priv_data;
> +    int size_temp = size;
> +    int pktsize, pkttype;
> +    uint32_t ts;
> +    const uint8_t *buf_temp = buf;
> +
> +    if (size > 11) {
> +        do {
> +            if (!rt->flv_off) {
> +                //skip flv header
> +                if (buf_temp[0] == 'F' && buf_temp[1] == 'L' && buf_temp[2] == 'V') {
> +                    buf_temp += 9 + 4;
> +                    size_temp -= 9 + 4;
> +                }
> +
> +                pkttype = bytestream_get_byte(&buf_temp);
> +                pktsize = bytestream_get_be24(&buf_temp);
> +                ts = bytestream_get_be24(&buf_temp);
> +                ts |= bytestream_get_byte(&buf_temp) << 24;
> +                bytestream_get_be24(&buf_temp);
> +                size_temp -= 11;
> +                rt->flv_size = pktsize;
> +
> +                //force 12bytes header
> +                if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
> +                    pkttype == RTMP_PT_NOTIFY) {
> +                    if (pkttype == RTMP_PT_NOTIFY)
> +                        pktsize += 16;
> +                    rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
> +                }
> +
> +                //crutch: can be big packet (128k), better to send it right here.

//this can be a big packet, it's better to send it right here

> +                ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL, pkttype, ts, pktsize);
> +                rt->out_pkt.extra = rt->main_channel_id;
> +                rt->flv_data = rt->out_pkt.data;
> +
> +                if (pkttype == RTMP_PT_NOTIFY)
> +                    ff_amf_write_string(&rt->flv_data, "@setDataFrame");
> +            }
> +
> +            if (rt->flv_size - rt->flv_off > size_temp) {
> +                bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
> +                rt->flv_off += size_temp;
> +            } else {
> +                bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
> +                rt->flv_off += rt->flv_size - rt->flv_off;
> +            }
> +
> +            if (rt->flv_off == rt->flv_size) {
> +                bytestream_get_be32(&buf_temp);
> +
> +                ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
> +                ff_rtmp_packet_destroy(&rt->out_pkt);
> +                rt->flv_size = 0;
> +                rt->flv_off = 0;
> +            }
> +        } while (buf_temp - buf < size_temp);
> +        return size;
> +    } else {
> +        //close connection here
> +        if (rt->out_pkt.data_size) {
> +            ff_rtmp_packet_destroy(&rt->out_pkt);
> +            rt->flv_size = 0;
> +            rt->flv_off = 0;
> +        }
> +
> +        av_log(LOG_CONTEXT, AV_LOG_DEBUG, "UnPublishing stream...\n");
> +        ff_rtmp_packet_create(&rt->out_pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
> +        rt->flv_data = rt->out_pkt.data;
> +        ff_amf_write_string(&rt->flv_data, "FCUnpublish");
> +        ff_amf_write_number(&rt->flv_data, 5.0);
> +        ff_amf_write_null(&rt->flv_data);
> +        ff_amf_write_string(&rt->flv_data, rt->playpath);
> +        rt->out_pkt.data_size = rt->flv_data - rt->out_pkt.data;
> +
> +        ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
> +        ff_rtmp_packet_destroy(&rt->out_pkt);
> +        return size;
> +    }
>  }
>  
>  URLProtocol rtmp_protocol = {

Ahem, why are doing this? There is rtmp_close() for final calls, and why
that if(size > 11) condition?



More information about the ffmpeg-devel mailing list