Изменить RTMP внутри libavformat FFmpeg

Мне нужно отправить сообщение Stream Dry на RTMP-сервер, на который мое приложение выполняет потоковую передачу. Я создал новую функцию, объявленную в avformat.h и определенную в rtmpproto.c, которая содержит следующее:

int av_send_rtmp_streamdry(struct URLContext *s) {
RTMPContext *rt = s->priv_data;
PutByteContext pbc;
RTMPPacket spkt = { 0 };
int ret;
uint8_t *p;

av_log(s, AV_LOG_INFO, "%p", rt);

// Create StreamDry packet
// The packet type is the same as the PING response type. From RTMP spec,
// packet type 4 belongs to User Control Messages.
// The packet size is Event Type (16 bits / 2 bytes) + Stream ID (4 bytes)
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;
}
p = spkt.data;
bytestream2_init_writer(&pbc, spkt.data, spkt.size);
bytestream2_put_be16(&pbc, 2);          // 2 -> Stream Dry
bytestream2_put_be32(&pbc, rt->stream_id);
spkt.size = p - spkt.data;
ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
                           &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);

if(ret != 0){
    av_log(NULL, AV_LOG_ERROR, "Stream Dry packet could not be sent");
    return ret;
}

ff_rtmp_packet_destroy(&spkt);

return 0;}

Я получаю URLContext через static_cast<URLContext*>(ofmt_ctx->pb->opaque) где ofmt мой AVFormatContext. Я вызываю этот метод непосредственно из моей программы, но проблема в том, что содержимое s->priv_data вряд ли когда-либо является допустимым указателем.

Как я могу это реализовать?

1 ответ

Решение

Наконец-то я смог реализовать эту функцию. Проблема заключалась в том, что проблема была связана с попыткой получить RTMPContext из AVFormatContext.

Поле AVFormatContext 'pb' содержит AVIOContext*.

Поле AVIOContext 'opaque' содержит пустоту *, но в моем случае (я не знаю, всегда ли это так) - AVIOInternal*. AVIOInternal содержит URLContext*, который мне нужен, но поскольку он определен в файле aviobuf.c, я не могу получить к нему доступ, но он содержит только одно поле. Таким образом, решение состоит в том, чтобы обойти структуру AVIOInternal, приводящую непрозрачное поле от AVIOContext к URLContext**. Таким образом, следующий код является решением:

AVIOContext *io = output->pb;
URLContext *url = *((URLContext**)(io->opaque));
RTMPContext *rt =(RTMPContext*)(url->priv_data);

РЕДАКТИРОВАТЬ: Это полный рабочий код.

int av_send_rtmp_streamdry(AVFormatContext *output) {
    AVIOContext *io = output->pb;
    URLContext *url = *((URLContext**)(io->opaque));
    RTMPContext *rt =(RTMPContext*)(url->priv_data);
    PutByteContext pbc;
    RTMPPacket spkt = { 0 };
    int ret;
    uint8_t *p;

    // Create StreamDry packet
    // The packet type is the same as the PING response type. From RTMP spec,
    // packet type 4 belongs to User Control Messages.
    // The packet size is Event Type (16 bits / 2 bytes) + Stream ID (4 bytes)
    if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
                                     RTMP_PT_PING, 0, 6)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Unable to create response packet\n");
        return ret;
    }
    bytestream2_init_writer(&pbc, spkt.data, spkt.size);
    bytestream2_put_be16(&pbc, 2);          // 2 -> Stream Dry
    bytestream2_put_be32(&pbc, rt->stream_id);
    ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
                               &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
    ff_rtmp_packet_destroy(&spkt);

    if(ret < 0){
        av_log(NULL, AV_LOG_ERROR, "Stream Dry packet could not be sent");
        return ret;
    }

    return 0;
}
Другие вопросы по тегам