函数rtmp_read()

FFMPEG版本为3.2 release。

libavformat/rtmpproto.c

函数rtmp_read()调用关系

avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts) ->

init_input(s, filename, &tmp) ->

av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->format_probesize) ->

avio_read(pb, buf + buf_offset, probe_size - buf_offset) ->

fill_buffer(s) ->

s->read_packet(s->opaque, dst, len) 实际回调函数io_read_packet() ->

ffurl_read(internal->h, buf, buf_size) ->

retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read) ->

transfer_func(h, buf + len, size - len) 实际回调函数rtmp_read()

第一次执行到rtmp_read()时,栈信息:

(gdb) bt
#0  rtmp_read (s=0x2768fc0, buf=0x276b8a0 "", size=32768) at libavformat/rtmpproto.c:2905
#1  0x00000000005f3744 in retry_transfer_wrapper (h=0x2768fc0, buf=0x276b8a0 "", size=32768) at libavformat/avio.c:378
#2  ffurl_read (h=0x2768fc0, buf=0x276b8a0 "", size=32768) at libavformat/avio.c:411
#3  0x00000000005f4cac in fill_buffer (s=0x276a460) at libavformat/aviobuf.c:540
#4  0x00000000005f4f80 in avio_read (s=0x276a460, buf=0x276a7f0 "\030-Y\002", size=2048) at libavformat/aviobuf.c:634
#5  0x000000000061ba07 in av_probe_input_buffer2 (pb=0x276a460, fmt=0x27686e8, filename=<value optimized out>, logctx=0x27686e0, offset=0, max_probe_size=1048576)
    at libavformat/format.c:314
#6  0x00000000007044ef in init_input (ps=0x7fffffffdbd8, filename=0x7fffffffe759 "rtmp://223.203.1.34:1936/live?vhost=cc.com/stream_1", fmt=<value optimized out>, options=0x2768428)
    at libavformat/utils.c:420
#7  avformat_open_input (ps=0x7fffffffdbd8, filename=0x7fffffffe759 "rtmp://223.203.1.34:1936/live?vhost=cc.com/stream_1", fmt=<value optimized out>, options=0x2768428)
    at libavformat/utils.c:529
#8  0x000000000047e65a in open_input_file (o=0x7fffffffdc80, filename=<value optimized out>) at ffmpeg_opt.c:997
#9  0x000000000047bb76 in open_files (l=0x2767998, inout=0x18b68a6 "input", open_file=0x47e220 <open_input_file>) at ffmpeg_opt.c:3135
#10 0x000000000047bde7 in ffmpeg_parse_options (argc=<value optimized out>, argv=<value optimized out>) at ffmpeg_opt.c:3175
#11 0x00000000004927c4 in main (argc=12, argv=0x7fffffffe488) at ffmpeg.c:4564

 

rtmp_read()函数体

static int rtmp_read(URLContext *s, uint8_t *buf, int size)
{
    RTMPContext *rt = s->priv_data;
    int orig_size = size;
    int ret;

    while (size > 0) {
        int data_left = rt->flv_size - rt->flv_off;

        if (data_left >= size) {
            memcpy(buf, rt->flv_data + rt->flv_off, size);
            rt->flv_off += size;
            return orig_size;
        }
        if (data_left > 0) {
            memcpy(buf, rt->flv_data + rt->flv_off, data_left);
            buf  += data_left;
            size -= data_left;
            rt->flv_off = rt->flv_size;
            return data_left;
        }
        if ((ret = get_packet(s, 0)) < 0)
           return ret;
    }
    return orig_size;
}

 

get_packet()函数

与服务器端交互,直到接收到音视频数据,或者metadata数据

/**
 * Interact with the server by receiving and sending RTMP packets until
 * there is some significant data (media data or expected status notification).
 *
 * @param s          reading context
 * @param for_header non-zero value tells function to work until it
 * gets notification from the server that playing has been started,
 * otherwise function will work until some media data is received (or
 * an error happens)
 * @return 0 for successful operation, negative value in case of error
 */
static int get_packet(URLContext *s, int for_header)
{
    RTMPContext *rt = s->priv_data;
    int ret;

    if (rt->state == STATE_STOPPED)
        return AVERROR_EOF;

    for (;;) {
        RTMPPacket rpkt = { 0 };
        if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
                                       rt->in_chunk_size, &rt->prev_pkt[0],
                                       &rt->nb_prev_pkt[0])) <= 0) {
            if (ret == 0) {
                return AVERROR(EAGAIN);
            } else {
                return AVERROR(EIO);
            }
        }

        // Track timestamp for later use
        rt->last_timestamp = rpkt.timestamp;

        rt->bytes_read += ret;
        if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
            av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
            if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
                return ret;
            rt->last_bytes_read = rt->bytes_read;
        }

        ret = rtmp_parse_result(s, rt, &rpkt);

        // At this point we must check if we are in the seek state and continue
        // with the next packet. handle_invoke will get us out of this state
        // when the right message is encountered
        if (rt->state == STATE_SEEKING) {
            ff_rtmp_packet_destroy(&rpkt);
            // We continue, let the natural flow of things happen:
            // AVERROR(EAGAIN) or handle_invoke gets us out of here
            continue;
        }

        if (ret < 0) {//serious error in current packet
            ff_rtmp_packet_destroy(&rpkt);
            return ret;
        }
        if (rt->do_reconnect && for_header) {
            ff_rtmp_packet_destroy(&rpkt);
            return 0;
        }
        if (rt->state == STATE_STOPPED) {
            ff_rtmp_packet_destroy(&rpkt);
            return AVERROR_EOF;
        }
        if (for_header && (rt->state == STATE_PLAYING    ||
                           rt->state == STATE_PUBLISHING ||
                           rt->state == STATE_SENDING    ||
                           rt->state == STATE_RECEIVING)) {
            ff_rtmp_packet_destroy(&rpkt);
            return 0;
        }
        if (!rpkt.size || !rt->is_input) {
            ff_rtmp_packet_destroy(&rpkt);
            continue;
        }
        if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
            ret = append_flv_data(rt, &rpkt, 0);
            ff_rtmp_packet_destroy(&rpkt);
            return ret;
        } else if (rpkt.type == RTMP_PT_NOTIFY) {
            ret = handle_notify(s, &rpkt);
            ff_rtmp_packet_destroy(&rpkt);
            return ret;
        } else if (rpkt.type == RTMP_PT_METADATA) {
            ret = handle_metadata(rt, &rpkt);
            ff_rtmp_packet_destroy(&rpkt);
            return 0;
        }
        ff_rtmp_packet_destroy(&rpkt);
    }
}

 

转载于:https://my.oschina.net/u/2326611/blog/808229

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值