从 tcp 服务器打开 8MP H264 流时出现问题
Issue in opening the 8MP H264 Stream from tcp server
我在 Qt 应用程序中从 Android 通过 tcp 服务器打开 8MP 分辨率的原始 h264 流时遇到问题。要在 ffplay 中打开流,我在终端中给出以下命令并且它能够播放它
ffplay -f h264 -codec:v h264 -probesize 32M <tcp://ipaddress:port>
但是当我尝试在 Qt 应用程序中打开流时,avformat_open_input() 给出错误 Invalid data found while processing input.
下面是我在 Qt 应用程序中使用的代码:
av_register_all();
avcodec_register_all();
avformat_network_init();
AVFormatContext *refrenceFormatCtx = NULL;
SwsContext *img_convert_ctx;
AVIOContext *avio_ctx = NULL;
int video_stream_index = 0;
AVCodecContext* codec_ctx = NULL;
AVSampleFormat *fmt = NULL;
char errorsdef[100];
AVDictionary *options = NULL;
av_dict_set(&options, "video_size","3264x2448",0);
av_dict_set(&options,"pixel_format","yuv420p",0);
av_dict_set(&options, "f", "h264", 0);
av_dict_set(&options, "codec:v", "h264", 0);
av_dict_set(&options, "codec:a", "aac", 0);
av_dict_set(&options, "probesize", "32M", 0);
int err = avformat_open_input(&refrenceFormatCtx,"tcp://192.168.42.129:2226", NULL, &options);
av_strerror(err,errorsdef,100);
qDebug() << "OPening Stream error: "<< err << " "<< errorsdef;
if(err<0)
abort();
av_dict_free(&options);
avformat_open_input设置选项的路径是否正确?我设置的参数是否正确?
我得到了上述问题的答案。问题代码和从 8MP 分辨率的原始 H.264 帧中获取 rgb 帧的代码如下:
avcodec_register_all();
av_register_all();
avformat_network_init();
AVDictionary *options = NULL;
AVFormatContext *refrenceFormatCtx = NULL;
AVInputFormat *fmts = av_find_input_format("h264");
char errorsdef[100];
AVCodecContext* codec_ctx = NULL;
int video_stream_index = 0;
SwsContext *img_convert_ctx = NULL;
AVFrame* picture_yuv = NULL;
AVFrame* picture_rgb = NULL;
uint8_t* picture_buffer_rgb;
uint8_t *rgb_image_data;
int sizeofrgbpicture = 0;
int initialize_rgb_requirements=1;
picture_yuv = av_frame_alloc();
av_dict_set(&options, "flags", "bicubic", 0);
av_opt_set(refrenceFormatCtx,"f","h264", AV_OPT_SEARCH_CHILDREN);
av_opt_set(refrenceFormatCtx,"codec:v","h264",AV_OPT_SEARCH_CHILDREN);
av_opt_set(refrenceFormatCtx,"probesize","32M", AV_OPT_SEARCH_CHILDREN);
// Open video file
int err = avformat_open_input(&refrenceFormatCtx,"tcp://192.168.42.129:2226", fmts, &options);
if (!options) {
int dict_count = av_dict_count(options);
qDebug() << "dict_count " << dict_count;
}
av_strerror(err,errorsdef,100);
qDebug() << "OPening Stream error: "<< err << " "<< errorsdef;
if (refrenceFormatCtx!=NULL){
err = avformat_find_stream_info(refrenceFormatCtx, &options);
if( err< 0){
av_strerror(err,errorsdef,100);
qDebug() << "Not able to find stream: "<< err << " "<< errorsdef;
}
}else{
qDebug() << "referencecontext null";
exit(1);
}
//search video stream
for (int i = 0; i < (int)refrenceFormatCtx->nb_streams; i++) {
AVStream* s = refrenceFormatCtx->streams[i];
if (s->codec == NULL){
continue;
}
codec_ctx = (s->codec);
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO){
video_stream_index = i;
}
}
AVPacket packet;
av_init_packet(&packet);
//open output file
AVFormatContext* output_ctx = avformat_alloc_context();
AVStream* stream = NULL;
//start reading packets from stream and emit data pointer to slot
av_read_play(refrenceFormatCtx); //play RTSP
avcodec_copy_context(codec_ctx, refrenceFormatCtx->streams[video_stream_index]->codec);
if (avcodec_open2(codec_ctx, avcodec_find_decoder(AV_CODEC_ID_H264), NULL) < 0){
qDebug() << "avcodec_open2 null";
}
while (av_read_frame(refrenceFormatCtx, &packet) >= 0) {
if (packet.stream_index == video_stream_index) { //packet is video
if (stream == NULL) { //create stream in file
stream = avformat_new_stream(output_ctx, refrenceFormatCtx->streams[video_stream_index]->codec->codec);
avcodec_copy_context(stream->codec, refrenceFormatCtx->streams[video_stream_index]->codec);
stream->sample_aspect_ratio = refrenceFormatCtx->streams[video_stream_index]->codec->sample_aspect_ratio;
}
int check = 0;
packet.stream_index = stream->id;
int result = avcodec_decode_video2(codec_ctx, picture_yuv, &check, &packet);
av_free_packet(&packet);
av_packet_unref(&packet);
if(result <= 0 || check == 0){
continue;
}
if(initialize_rgb_requirements)
{
sizeofrgbpicture = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height);
picture_rgb = av_frame_alloc();
picture_buffer_rgb = (uint8_t*) (av_malloc(sizeofrgbpicture));
avpicture_fill((AVPicture *) picture_rgb, picture_buffer_rgb, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height);
img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
initialize_rgb_requirements=0;
}
int height = 0;
if(picture_yuv->data != NULL)
{
height = sws_scale(img_convert_ctx, ((AVPicture*)picture_yuv)->data, ((AVPicture*)picture_yuv)->linesize, 0, codec_ctx->height, ((AVPicture*)picture_rgb)->data,((AVPicture*)picture_rgb)->linesize);
}
rgb_image_data = (uint8_t *)malloc(sizeofrgbpicture * sizeof(uint8_t));
int ret = avpicture_layout((AVPicture *)picture_rgb, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, rgb_image_data, sizeofrgbpicture);
emit imageQueued(rgb_image_data, codec_ctx->width,codec_ctx->height);
}
msleep(1);
}
av_freep(picture_buffer_rgb);
av_frame_free(&picture_rgb);
avio_close(output_ctx->pb);
avformat_free_context(output_ctx);
avformat_close_input(&refrenceFormatCtx);
我开始知道对于原始 H.264 流我们必须告诉 ffmpeg 格式是 h264。为此,我使用 AVInputFormat
,设置其他选项,如视频编解码器和探测大小,我使用 av_op_set()
。为了在 ffmpeg 中设置默认标志,我使用了 av_dict_set()
。我已将数据指针发送到我所需的插槽。如果有人想从它创建一个文件,那么它可以通过将这个指针写入文件来生成.ppm文件。
我在 Qt 应用程序中从 Android 通过 tcp 服务器打开 8MP 分辨率的原始 h264 流时遇到问题。要在 ffplay 中打开流,我在终端中给出以下命令并且它能够播放它
ffplay -f h264 -codec:v h264 -probesize 32M <tcp://ipaddress:port>
但是当我尝试在 Qt 应用程序中打开流时,avformat_open_input() 给出错误 Invalid data found while processing input. 下面是我在 Qt 应用程序中使用的代码:
av_register_all();
avcodec_register_all();
avformat_network_init();
AVFormatContext *refrenceFormatCtx = NULL;
SwsContext *img_convert_ctx;
AVIOContext *avio_ctx = NULL;
int video_stream_index = 0;
AVCodecContext* codec_ctx = NULL;
AVSampleFormat *fmt = NULL;
char errorsdef[100];
AVDictionary *options = NULL;
av_dict_set(&options, "video_size","3264x2448",0);
av_dict_set(&options,"pixel_format","yuv420p",0);
av_dict_set(&options, "f", "h264", 0);
av_dict_set(&options, "codec:v", "h264", 0);
av_dict_set(&options, "codec:a", "aac", 0);
av_dict_set(&options, "probesize", "32M", 0);
int err = avformat_open_input(&refrenceFormatCtx,"tcp://192.168.42.129:2226", NULL, &options);
av_strerror(err,errorsdef,100);
qDebug() << "OPening Stream error: "<< err << " "<< errorsdef;
if(err<0)
abort();
av_dict_free(&options);
avformat_open_input设置选项的路径是否正确?我设置的参数是否正确?
我得到了上述问题的答案。问题代码和从 8MP 分辨率的原始 H.264 帧中获取 rgb 帧的代码如下:
avcodec_register_all();
av_register_all();
avformat_network_init();
AVDictionary *options = NULL;
AVFormatContext *refrenceFormatCtx = NULL;
AVInputFormat *fmts = av_find_input_format("h264");
char errorsdef[100];
AVCodecContext* codec_ctx = NULL;
int video_stream_index = 0;
SwsContext *img_convert_ctx = NULL;
AVFrame* picture_yuv = NULL;
AVFrame* picture_rgb = NULL;
uint8_t* picture_buffer_rgb;
uint8_t *rgb_image_data;
int sizeofrgbpicture = 0;
int initialize_rgb_requirements=1;
picture_yuv = av_frame_alloc();
av_dict_set(&options, "flags", "bicubic", 0);
av_opt_set(refrenceFormatCtx,"f","h264", AV_OPT_SEARCH_CHILDREN);
av_opt_set(refrenceFormatCtx,"codec:v","h264",AV_OPT_SEARCH_CHILDREN);
av_opt_set(refrenceFormatCtx,"probesize","32M", AV_OPT_SEARCH_CHILDREN);
// Open video file
int err = avformat_open_input(&refrenceFormatCtx,"tcp://192.168.42.129:2226", fmts, &options);
if (!options) {
int dict_count = av_dict_count(options);
qDebug() << "dict_count " << dict_count;
}
av_strerror(err,errorsdef,100);
qDebug() << "OPening Stream error: "<< err << " "<< errorsdef;
if (refrenceFormatCtx!=NULL){
err = avformat_find_stream_info(refrenceFormatCtx, &options);
if( err< 0){
av_strerror(err,errorsdef,100);
qDebug() << "Not able to find stream: "<< err << " "<< errorsdef;
}
}else{
qDebug() << "referencecontext null";
exit(1);
}
//search video stream
for (int i = 0; i < (int)refrenceFormatCtx->nb_streams; i++) {
AVStream* s = refrenceFormatCtx->streams[i];
if (s->codec == NULL){
continue;
}
codec_ctx = (s->codec);
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO){
video_stream_index = i;
}
}
AVPacket packet;
av_init_packet(&packet);
//open output file
AVFormatContext* output_ctx = avformat_alloc_context();
AVStream* stream = NULL;
//start reading packets from stream and emit data pointer to slot
av_read_play(refrenceFormatCtx); //play RTSP
avcodec_copy_context(codec_ctx, refrenceFormatCtx->streams[video_stream_index]->codec);
if (avcodec_open2(codec_ctx, avcodec_find_decoder(AV_CODEC_ID_H264), NULL) < 0){
qDebug() << "avcodec_open2 null";
}
while (av_read_frame(refrenceFormatCtx, &packet) >= 0) {
if (packet.stream_index == video_stream_index) { //packet is video
if (stream == NULL) { //create stream in file
stream = avformat_new_stream(output_ctx, refrenceFormatCtx->streams[video_stream_index]->codec->codec);
avcodec_copy_context(stream->codec, refrenceFormatCtx->streams[video_stream_index]->codec);
stream->sample_aspect_ratio = refrenceFormatCtx->streams[video_stream_index]->codec->sample_aspect_ratio;
}
int check = 0;
packet.stream_index = stream->id;
int result = avcodec_decode_video2(codec_ctx, picture_yuv, &check, &packet);
av_free_packet(&packet);
av_packet_unref(&packet);
if(result <= 0 || check == 0){
continue;
}
if(initialize_rgb_requirements)
{
sizeofrgbpicture = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height);
picture_rgb = av_frame_alloc();
picture_buffer_rgb = (uint8_t*) (av_malloc(sizeofrgbpicture));
avpicture_fill((AVPicture *) picture_rgb, picture_buffer_rgb, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height);
img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
initialize_rgb_requirements=0;
}
int height = 0;
if(picture_yuv->data != NULL)
{
height = sws_scale(img_convert_ctx, ((AVPicture*)picture_yuv)->data, ((AVPicture*)picture_yuv)->linesize, 0, codec_ctx->height, ((AVPicture*)picture_rgb)->data,((AVPicture*)picture_rgb)->linesize);
}
rgb_image_data = (uint8_t *)malloc(sizeofrgbpicture * sizeof(uint8_t));
int ret = avpicture_layout((AVPicture *)picture_rgb, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, rgb_image_data, sizeofrgbpicture);
emit imageQueued(rgb_image_data, codec_ctx->width,codec_ctx->height);
}
msleep(1);
}
av_freep(picture_buffer_rgb);
av_frame_free(&picture_rgb);
avio_close(output_ctx->pb);
avformat_free_context(output_ctx);
avformat_close_input(&refrenceFormatCtx);
我开始知道对于原始 H.264 流我们必须告诉 ffmpeg 格式是 h264。为此,我使用 AVInputFormat
,设置其他选项,如视频编解码器和探测大小,我使用 av_op_set()
。为了在 ffmpeg 中设置默认标志,我使用了 av_dict_set()
。我已将数据指针发送到我所需的插槽。如果有人想从它创建一个文件,那么它可以通过将这个指针写入文件来生成.ppm文件。