ffmpeg应用实例:从拉流到推流(改进版)

    xiaoxiao2021-03-25  111

    说明:

    1、使用 rtmp地址 和 rtsp地址 测试,程序可运行,生成的flv文件可用VLC播放器播放;

    2、音频和视频有些不同步;

    3、网络推流不稳定,还有问题待解决;

    #include "stdafx.h" extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libswresample/swresample.h" }; #include "opencv2/opencv.hpp" #ifdef _DEBUG #pragma comment(lib, "opencv_ts300d.lib") #pragma comment(lib, "opencv_world300d.lib") #else #pragma comment(lib, "opencv_ts300.lib") #pragma comment(lib, "opencv_world300.lib") #endif #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avformat.lib") #pragma comment(lib, "avutil.lib") #pragma comment(lib, "swscale.lib") #pragma comment(lib, "swresample.lib") #define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48KHZ 32bit audio -> 32bit / 8 * 48000 * 1 = 192000 Byte #define SAVE_FILE 0 /* 函数功能:将图片 foreground 叠加到图片 background 上 */ static void overlayImage(const cv::Mat &background, const cv::Mat &foreground, cv::Mat &output, cv::Point2i location) { background.copyTo(output); for (int y = std::max(location.y, 0); y < background.rows; ++y) { int fY = y - location.y; if (fY >= foreground.rows) break; for (int x = std::max(location.x, 0); x < background.cols; ++x) { int fX = x - location.x; if (fX >= foreground.cols) break; double opacity = ((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3]) / 255.; for (int c = 0; opacity > 0 && c < output.channels(); ++c) { unsigned char foregroundPx = foreground.data[fY * foreground.step + fX * foreground.channels() + c]; unsigned char backgroundPx = background.data[y * background.step + x * background.channels() + c]; output.data[y*output.step + output.channels()*x + c] = backgroundPx * (1. - opacity) + foregroundPx * opacity; } } } } int main(int argc, char* argv[]) { AVFormatContext* ifmt_ctx = NULL; const char* input_filepath = NULL; AVFormatContext* ofmt_ctx = NULL; const char* output_filepath = NULL; int idx_audio = -1; int idx_video = -1; AVStream* istream_audio = NULL; AVCodecContext* codec_ctx_audio = NULL; AVCodec* codec_audio = NULL; AVStream* istream_video = NULL; AVCodecContext* codec_ctx_video = NULL; AVCodec* codec_video = NULL; AVStream* ostream_video = NULL; AVStream* ostream_audio = NULL; AVCodecContext* codec_ctx_2h264 = NULL; AVCodecContext* codec_ctx_2aac = NULL; struct SwsContext* img_convert_ctx_2bgr = NULL; struct SwsContext* img_convert_ctx_2yuv = NULL; uint8_t* buffer_bgr = NULL; uint8_t* buffer_yuv = NULL; struct SwrContext* au_convert_ctx = NULL; uint8_t* out_audio_buffer = NULL; av_register_all(); avformat_network_init(); //input_filepath = "rtmp://live.hkstv.hk.lxdns.com/live/hks"; input_filepath = "rtsp://admin:q12345678@192.168.1.102:554/MPEG-4/ch1/main/av_stream"; //output_filepath = "rtmp://127.0.0.1/live/mytest"; output_filepath = "output.flv"; AVDictionary* options = NULL; av_dict_set(&options, "rtsp_transport", "tcp", 0); if (avformat_open_input(&ifmt_ctx, input_filepath, NULL, &options) < 0) { printf("error: avformat_open_input\n"); goto END; } if (avformat_find_stream_info(ifmt_ctx, NULL) < 0) { printf("error: avformat_find_stream_info\n"); goto END; } if (avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", output_filepath) < 0) { printf("error: avformat_alloc_output_context2\n"); goto END; } for (int i = 0; i < ifmt_ctx->nb_streams; i++) { if (AVMEDIA_TYPE_AUDIO == ifmt_ctx->streams[i]->codec->codec_type) { idx_audio = i; istream_audio = ifmt_ctx->streams[idx_audio]; codec_ctx_audio = istream_audio->codec; ostream_audio = avformat_new_stream(ofmt_ctx, istream_audio->codec->codec); avcodec_copy_context(ostream_audio->codec, istream_audio->codec); ostream_audio->time_base = istream_audio->time_base; ostream_audio->codec->codec_tag = 0; if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) ostream_audio->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; } else if (AVMEDIA_TYPE_VIDEO == ifmt_ctx->streams[i]->codec->codec_type) { idx_video = i; istream_video = ifmt_ctx->streams[idx_video]; codec_ctx_video = istream_video->codec; ostream_video = avformat_new_stream(ofmt_ctx, istream_video->codec->codec); avcodec_copy_context(ostream_video->codec, istream_video->codec); ostream_video->time_base = istream_video->time_base; ostream_video->codec->codec_tag = 0; if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) ostream_video->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; } else { ; } } if (idx_video < 0 || idx_audio < 0) { printf("error: can not find any audio stream or video stream\n"); goto END; } codec_audio = avcodec_find_decoder(codec_ctx_audio->codec_id); if (NULL == codec_audio) { printf("error: avcodec_find_decoder, input audio\n"); goto END; } codec_video = avcodec_find_decoder(codec_ctx_video->codec_id); if (NULL == codec_video) { printf("error: avcodec_find_decoder, input video\n"); goto END; } if (avcodec_open2(codec_ctx_audio, codec_audio, NULL) < 0) // 打开输入音频流的解码器 { printf("error: avcodec_open2, input audio\n"); goto END; } if (avcodec_open2(codec_ctx_video, codec_video, NULL) < 0) // 打开输入视频流的解码器 { printf("error: avcodec_open2, input video\n"); goto END; } if (avio_open(&ofmt_ctx->pb, output_filepath, AVIO_FLAG_WRITE) < 0) { printf("error: avio_open\n"); goto END; } if (avformat_write_header(ofmt_ctx, NULL) < 0) { printf("error: avformat_write_header\n"); goto END; } av_dump_format(ifmt_ctx, -1, input_filepath, 0); av_dump_format(ofmt_ctx, -1, output_filepath, 1); AVFrame  oframe_bgr = { 0 }; oframe_bgr.width = codec_ctx_video->width; oframe_bgr.height = codec_ctx_video->height; oframe_bgr.format = AV_PIX_FMT_BGR24; int pic_size_bgr = avpicture_get_size((AVPixelFormat)oframe_bgr.format, oframe_bgr.width, oframe_bgr.height); buffer_bgr = (uint8_t*)av_malloc(pic_size_bgr); avpicture_fill((AVPicture*)&oframe_bgr, buffer_bgr, (AVPixelFormat)oframe_bgr.format, oframe_bgr.width, oframe_bgr.height); img_convert_ctx_2bgr = sws_getContext(codec_ctx_video->width, codec_ctx_video->height, codec_ctx_video->pix_fmt, oframe_bgr.width, oframe_bgr.height, (AVPixelFormat)oframe_bgr.format, SWS_BICUBIC, NULL, NULL, NULL); AVFrame  oframe_yuv = { 0 }; oframe_yuv.width = codec_ctx_video->width; oframe_yuv.height = codec_ctx_video->height; oframe_yuv.format = AV_PIX_FMT_YUV420P; int pic_size_yuv = avpicture_get_size((AVPixelFormat)oframe_yuv.format, oframe_yuv.width, oframe_yuv.height); buffer_yuv = (uint8_t*)av_malloc(pic_size_yuv); avpicture_fill((AVPicture*)&oframe_yuv, buffer_yuv, (AVPixelFormat)oframe_yuv.format, oframe_yuv.width, oframe_yuv.height); img_convert_ctx_2yuv = sws_getContext(oframe_bgr.width, oframe_bgr.height, (AVPixelFormat)oframe_bgr.format, oframe_yuv.width, oframe_yuv.height, (AVPixelFormat)oframe_yuv.format, SWS_BICUBIC, NULL, NULL, NULL); int64_t in_audio_channel_layout = av_get_default_channel_layout(codec_ctx_audio->channels); AVSampleFormat in_audio_sample_fmt = codec_ctx_audio->sample_fmt; int in_audio_sample_rate = codec_ctx_audio->sample_rate; AVSampleFormat out_audio_sample_fmt = AV_SAMPLE_FMT_S16; int out_audio_sample_rate = 44100; // <= 48000 HZ ? int out_audio_nb_samples = codec_ctx_audio->frame_size; // AAC:1024  MP3:1152   uint64_t out_audio_channel_layout = AV_CH_LAYOUT_STEREO; int out_audio_channels = av_get_channel_layout_nb_channels(out_audio_channel_layout); int out_audio_buffer_size = av_samples_get_buffer_size(NULL, out_audio_channels, out_audio_nb_samples, out_audio_sample_fmt, 1); out_audio_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * out_audio_channels); au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_audio_channel_layout, out_audio_sample_fmt, out_audio_sample_rate, in_audio_channel_layout, in_audio_sample_fmt, in_audio_sample_rate, 0, NULL); swr_init(au_convert_ctx); AVCodec* codec_2h264 = NULL; AVCodecID codec_id_2h264; codec_id_2h264 = AV_CODEC_ID_H264; codec_2h264 = avcodec_find_encoder(codec_id_2h264); codec_ctx_2h264 = avcodec_alloc_context3(codec_2h264); codec_ctx_2h264->codec_type = AVMEDIA_TYPE_VIDEO; codec_ctx_2h264->pix_fmt = AV_PIX_FMT_YUV420P; codec_ctx_2h264->bit_rate = codec_ctx_video->bit_rate; // 0 ? codec_ctx_2h264->width = codec_ctx_video->width; codec_ctx_2h264->height = codec_ctx_video->height; codec_ctx_2h264->time_base = codec_ctx_video->time_base; if (avcodec_open2(codec_ctx_2h264, codec_2h264, NULL) < 0) { printf("error: avcodec_open2, output video\n"); goto END; } AVCodec* codec_2aac = NULL; AVCodecID codec_id_2aac; codec_id_2aac = AV_CODEC_ID_AAC; codec_2aac = avcodec_find_encoder(codec_id_2aac); codec_ctx_2aac = avcodec_alloc_context3(codec_2aac); codec_ctx_2aac->codec_type = AVMEDIA_TYPE_AUDIO; codec_ctx_2aac->sample_fmt = AV_SAMPLE_FMT_FLTP; codec_ctx_2aac->sample_rate = codec_ctx_audio->sample_rate; codec_ctx_2aac->bit_rate = codec_ctx_audio->bit_rate; codec_ctx_2aac->channel_layout = codec_ctx_audio->channel_layout; codec_ctx_2aac->channels = codec_ctx_audio->channels; codec_ctx_2aac->time_base = codec_ctx_audio->time_base; if (avcodec_open2(codec_ctx_2aac, codec_2aac, NULL) < 0) { printf("error: avcodec_open2, output audio\n"); goto END; } AVPacket ipkt = { 0 }; av_init_packet(&ipkt); ipkt.data = NULL; ipkt.size = 0; AVFrame  iframe_audio = { 0 }; AVFrame  iframe = { 0 }; AVPacket opkt_audio = { 0 }; av_init_packet(&opkt_audio); opkt_audio.data = NULL; opkt_audio.size = 0; AVPacket opkt = { 0 }; av_init_packet(&opkt); opkt.data = NULL; opkt.size = 0; #if SAVE_FILE FILE* output_bgr = fopen("output.bgr", "wb+"); FILE* output_yuv = fopen("output.yuv", "wb+"); FILE* output_h264 = fopen("output.h264", "wb+"); FILE* output_pcm = fopen("output.pcm", "wb+"); FILE* output_aac = fopen("output.aac", "wb+"); #endif while (1) { if (av_read_frame(ifmt_ctx, &ipkt) < 0) break; //if (0 == ipkt.pts) //{ // continue; //} if (ipkt.stream_index == idx_audio) { avcodec_send_packet(codec_ctx_audio, &ipkt); avcodec_receive_frame(codec_ctx_audio, &iframe_audio); swr_convert(au_convert_ctx, &out_audio_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t**)iframe_audio.data, iframe_audio.nb_samples); #if SAVE_FILE fwrite(out_audio_buffer, 1, out_audio_buffer_size, output_pcm); #endif iframe_audio.pts = ipkt.pts; avcodec_send_frame(codec_ctx_2aac, &iframe_audio); avcodec_receive_packet(codec_ctx_2aac, &opkt_audio); #if SAVE_FILE // 生成的AAC文件无法播放。待解! fwrite(opkt_audio.data, 1, opkt_audio.size, output_aac);  #endif opkt_audio.pts = av_rescale_q_rnd(ipkt.pts, istream_audio->time_base, ostream_audio->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); opkt_audio.dts = av_rescale_q_rnd(ipkt.dts, istream_audio->time_base, ostream_audio->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); opkt_audio.duration = av_rescale_q(ipkt.duration, istream_audio->time_base, ostream_audio->time_base); opkt_audio.pos = -1; opkt_audio.stream_index = idx_audio; av_interleaved_write_frame(ofmt_ctx, &opkt_audio); av_free_packet(&opkt_audio); static int audio_count = 0; printf(" audio count = %d\n", ++audio_count); } else if (ipkt.stream_index == idx_video) { avcodec_send_packet(codec_ctx_video, &ipkt); avcodec_receive_frame(codec_ctx_video, &iframe); sws_scale(img_convert_ctx_2bgr, (const uint8_t* const*)iframe.data, iframe.linesize, 0, iframe.height, oframe_bgr.data, oframe_bgr.linesize); cv::Mat background(oframe_bgr.height, oframe_bgr.width, CV_8UC3, oframe_bgr.data[0]); overlayImage(background, cv::imread("logo.jpg"), background, cv::Point(20, 30)); #if SAVE_FILE fwrite(oframe_bgr.data[0], (oframe_bgr.width) * (oframe_bgr.height) * 3, 1, output_bgr); #endif sws_scale(img_convert_ctx_2yuv, (const uint8_t* const*)oframe_bgr.data, oframe_bgr.linesize, 0, oframe_bgr.height, oframe_yuv.data, oframe_yuv.linesize); #if SAVE_FILE fwrite(oframe_yuv.data[0], (oframe_yuv.width) * (oframe_yuv.height), 1, output_yuv); fwrite(oframe_yuv.data[1], (oframe_yuv.width) * (oframe_yuv.height) / 4, 1, output_yuv); fwrite(oframe_yuv.data[2], (oframe_yuv.width) * (oframe_yuv.height) / 4, 1, output_yuv); #endif oframe_yuv.pts = ipkt.pts; oframe_yuv.width = codec_ctx_2h264->width; oframe_yuv.height = codec_ctx_2h264->height; avcodec_send_frame(codec_ctx_2h264, &oframe_yuv); avcodec_receive_packet(codec_ctx_2h264, &opkt); #if SAVE_FILE fwrite(opkt.data, 1, opkt.size, output_h264); #endif opkt.pts = av_rescale_q_rnd(ipkt.pts, istream_video->time_base, ostream_video->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); opkt.dts = av_rescale_q_rnd(ipkt.dts, istream_video->time_base, ostream_video->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); opkt.duration = av_rescale_q(ipkt.duration, istream_video->time_base, ostream_video->time_base); opkt.pos = -1; opkt.stream_index = idx_video; av_interleaved_write_frame(ofmt_ctx, &opkt); av_free_packet(&opkt); static int video_count = 0; printf("video_count = %d\n", ++video_count); } else { ; } av_free_packet(&ipkt); } if (0 != av_write_trailer(ofmt_ctx)) { printf("error: av_write_trailer\n"); goto END; } END: #if FILE if (NULL != output_pcm) fclose(output_pcm); if (NULL != output_aac) fclose(output_aac); if (NULL != output_bgr) fclose(output_bgr); if (NULL != output_yuv) fclose(output_yuv); if (NULL != output_h264) fclose(output_h264); #endif avformat_close_input(&ifmt_ctx); av_free(out_audio_buffer); av_free(buffer_bgr); av_free(buffer_yuv); swr_free(&au_convert_ctx); sws_freeContext(img_convert_ctx_2bgr); sws_freeContext(img_convert_ctx_2yuv); avcodec_free_context(&codec_ctx_2h264); avcodec_free_context(&codec_ctx_2aac); if (NULL != ofmt_ctx) avio_close(ofmt_ctx->pb); avformat_free_context(ofmt_ctx);     return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-20080.html

    最新回复(0)