2015-08-27 2 views
2

Я пытаюсь передать H.264 по UDP, пока не повезло. Вот минимальный код, который вы можете воспроизвести.Потоковая передача H.264 поверх UDP с использованием FFmpeg и ошибка «размеры не установлены»

Для компиляции,

g++ -o test -lavcodec -lavformat -lavutil test.cpp 

Дополнительная информация, я начинаю ffplay следующим образом. В настоящее время это бесполезно.

ffplay -i udp://127.0.0.1:8554/live.sdp 

Выход моего кода (см avio_open() вызов),

[libx264 @ 0x6a26c0] using mv_range_thread = 24 
[libx264 @ 0x6a26c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.1 Cache64 
[libx264 @ 0x6a26c0] profile High, level 3.1 
Output #0, h264, to 'udp://127.0.0.1:8554/live.sdp': 
    Stream #0:0, 0, 0/0: Video: h264 (libx264), -1 reference frame, none, q=-1--1 
[h264 @ 0x6a2020] dimensions not set 
Cannot write header to stream: Success 

И код,

extern "C" { 
    #include <libavcodec/avcodec.h> 
    #include <libavformat/avformat.h> 
    #include <libavutil/avutil.h> 
} 

#include <iostream> 
using namespace std; 

int main() { 
    AVCodecContext* m_codecContext; 
    AVCodec* m_codec; 
    AVFormatContext* m_formatContext; 
    AVStream* m_stream; 

    unsigned m_outWidth = 768; 
    unsigned m_outHeight = 608; 

    av_register_all(); 
    avcodec_register_all(); 
    avformat_network_init(); 

    int errorStatus = 0; 
    char errorLog[128] = { 0 }; 
    av_log_set_level(AV_LOG_TRACE); 

    string m_output("udp://127.0.0.1:8554/live.sdp"); 

    if (avformat_alloc_output_context2(&m_formatContext, NULL, "h264", m_output.c_str()) < 0) { 
     cerr << "Cannot allocate output context: " 
      << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

    AVOutputFormat *m_outputFormat = m_formatContext->oformat; 

    m_codec = avcodec_find_encoder(AV_CODEC_ID_H264); 
    if (!m_codec) { 
     cerr << "Cannot find an encoder: " 
      << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

    m_codecContext = avcodec_alloc_context3(m_codec); 
    if (!m_codecContext) { 
     cerr << "Cannot allocate a codec context: " 
      << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

    m_codecContext->pix_fmt = AV_PIX_FMT_YUV420P; 
    m_codecContext->width = m_outWidth; 
    m_codecContext->height = m_outHeight; 

    if (avcodec_open2(m_codecContext, m_codec, NULL) < 0) { 
     cerr << "Cannot open codec: " 
      << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

    m_stream = avformat_new_stream(m_formatContext, m_codec); 
    if (!m_stream) { 
     cerr << "Cannot create a new stream: " 
      << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

    av_dump_format(m_formatContext, 0, m_output.c_str(), 1); 

    if ((errorStatus = avio_open(&m_formatContext->pb, m_output.c_str(), AVIO_FLAG_WRITE)) < 0) { 
     cerr << "Cannot open output: " 
      << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

    if (avformat_write_header(m_formatContext, NULL) < 0) { 
     cerr << "Cannot write header to stream: " 
      << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

    cout << "All done." << endl; 

    return 0; 
} 

Для тех, кто имеет даже больше времени, чтобы сэкономить на моей проблеме, когда я изменение m_output до rtsp://127.0.0.1:8554/live.sdp и ffplay команда ffplay -rtsp_flags listen -i rtsp://127.0.0.1:8554/live.sdp Я получаю ошибку,

[libx264 @ 0x1e056c0] using mv_range_thread = 24 
[libx264 @ 0x1e056c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.1 Cache64 
[libx264 @ 0x1e056c0] profile High, level 3.1 
Output #0, h264, to 'rtsp://127.0.0.1:8554/live.sdp': 
    Stream #0:0, 0, 0/0: Video: h264 (libx264), -1 reference frame, none, q=-1--1 
Cannot open output: Protocol not found 

Могу ли я ожидать, что потоковый протокол будет изменен следующим образом?

ответ

0

Видимо я создавал и инициализации AVCodecContext, а затем не использовать его .. AVStream имеет свой собственный AVCodecContext (что вполне разумно, так как разные потоки, как правило, нуждаются в различных кодеров), и это был один, что мне нужно, чтобы инициализировать размеров и формата пикселей. Для этого мне также необходимо было поменять вызовы на avformat_new_stream() и avcodec_open2() и позвонить первым. Ниже приведено различие между исправлением.

Обратите внимание, что m_codecContext удален вообще.

--- rtsp-so.cpp.orig 2015-09-03 17:34:08.190375415 +0200 
+++ rtsp-so.cpp 2015-09-03 17:43:42.166542704 +0200 
@@ -8,7 +8,6 @@ 
using namespace std; 

int main() { 
- AVCodecContext* m_codecContext; 
    AVCodec* m_codec; 
    AVFormatContext* m_formatContext; 
    AVStream* m_stream; 
@@ -41,32 +40,25 @@ 
     return -1; 
    } 

- m_codecContext = avcodec_alloc_context3(m_codec); 
- if (!m_codecContext) { 
-  cerr << "Cannot allocate a codec context: " 
+ m_stream = avformat_new_stream(m_formatContext, m_codec); 
+ if (!m_stream) { 
+  cerr << "Cannot create a new stream: " 
       << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

- m_codecContext->pix_fmt = AV_PIX_FMT_YUV420P; 
- m_codecContext->width = m_outWidth; 
- m_codecContext->height = m_outHeight; 
+ av_dump_format(m_formatContext, 0, m_output.c_str(), 1); 

- if (avcodec_open2(m_codecContext, m_codec, NULL) < 0) { 
-  cerr << "Cannot open codec: " 
-    << av_make_error_string(errorLog, 128, errorStatus) << endl; 
-  return -1; 
- } 
+ m_stream->codec->pix_fmt = AV_PIX_FMT_YUV420P; 
+ m_stream->codec->width = m_outWidth; 
+ m_stream->codec->height = m_outHeight; 

- m_stream = avformat_new_stream(m_formatContext, m_codec); 
- if (!m_stream) { 
-  cerr << "Cannot create a new stream: " 
+ if (avcodec_open2(m_stream->codec, m_codec, NULL) < 0) { 
+  cerr << "Cannot open codec: " 
       << av_make_error_string(errorLog, 128, errorStatus) << endl; 
     return -1; 
    } 

- av_dump_format(m_formatContext, 0, m_output.c_str(), 1); 
- 
    if ((errorStatus = avio_open(&m_formatContext->pb, m_output.c_str(), AVIO_FLAG_WRITE)) < 0) { 
     cerr << "Cannot open output: " 
       << av_make_error_string(errorLog, 128, errorStatus) << endl; 
Смежные вопросы