Giter Site home page Giter Site logo

jackeylea / ffmpeg_beginner Goto Github PK

View Code? Open in Web Editor NEW
255.0 7.0 101.0 918 KB

食铁兽 ffmpeg4/5/6入门系列教程代码

Home Page: https://blog.jackeylea.com/ffmpeg/ffmpeg-learning-indexes

License: MIT License

QMake 6.57% C 27.70% C++ 64.73% QML 1.00%
ffmpeg video audio qt5 decode encode h264 yuv filters demuxer muxer codec ffmpeg4 ffmpeg5 ffmpeg6

ffmpeg_beginner's Introduction

ffmpeg_beginner

FFmpeg4入门系列教程代码

FFmpeg5/6对应代码见其他分支

编译说明

  • 使用FFmpeg-BuildsLatest Auto-Build (2023-09-04 12:49) 15d0b26 测试
  • 尽量保证编译结果没有错误、没有警告、没有deprecated方法调用
  • 如果提示系统没有mfx头文件,可以从Intel Media SDK下载,下载后把api/include目录重命名为mfx,然后复制到include目录中

源码说明

10.02.get_lib_version

获取库版本信息并解析输出可读信息

10.03.get_stream_info

输出视频的基本信息(时长、码率、编码方式等等)

10.04.video_decode_flow

视频解码的基本流程

10.05.video_decode_frame_save

解码视频并保存其中的50帧画面为ppm格式图片

10.06.video_decode_mp42yuv

视频解码的基本流程并输出视频信息,将解码后的视频数据保存为YUV格式文件

分别解码为YUV420P/YUV420SP

10.07.video_decode_by_cpu_display_by_qwidget

使用CPU解码视频,然后使用Qt的QWidget显示画面

10.08.video_decode_by_cpu_display_by_qopengl

使用CPU解码视频,然后使用Qt的QOpenGL显示画面

两种方法仅供参考

10.09.video_decode_by_cpu_display_by_qml

使用CPU解码视频,然后使用QML显示画面

10.10.video_decode_by_cuda_display_by_qt

使用CUDA解码视频并使用Qt的QWidget/QOpenGL/QML显示视频

10.11.video_encode_yuv2h264

将yuv源视频文件编码为h264格式的文件

10.12.video_encode_h2642mp4

将h264编码为mp4格式文件

10.13.video_encode_camera2h264

将摄像头捕获的视频直接编码为H264格式

10.14.audio_decode_mp32pcm

将mp3文件解码为pcm文件

10.15.audio_decode_swr_mp32pcm

将mp3音频重采样解码为pcm

10.16.audio_player_decode_by_ffmpeg_play_by_qt

使用FFmpeg解码音频,使用Qt播放音频

10.17.audio_player_decode_from_mem_play_by_qt

解码内存中的mp3数据并使用Qt播放

10.18.audio_encode_pcm2mp3

将pcm格式文件编码为mp3格式

10.19.audio_video_sync

Qt简单视频播放器,带音视频同步

10.20.video_decode_add_filter_display_by_qwidget

使用CPU解码视频,并添加滤镜,然后使用QWidget显示画面

10.21.video_demuxer_mp42h264mp3

将mp4分解为h264和mp3

10.22.video_demuxer_mp42yuvpcm

将mp4分解为h264和mp3,并在此基础上将h264解码为yuv,将mp3解码为pcm

10.23.video_muxer_mp3h2642mp4

将h264和mp3合并为mp4

RTSParser

收RTSP流,并解析流中的H264数据

待添加

本系列的目的就是将雷霄华同志的教程进行新版本适配,其在CSDN发布的所有文章涉及的代码都会进行适配

ffmpeg_beginner's People

Contributors

jackeylea avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ffmpeg_beginner's Issues

10.13例子改成屏幕,报错

`

int flush_encoder(AVFormatContext *fmtCtx, AVCodecContext *codecCtx, int vStreamIndex) {
 int ret = 0;
 AVPacket *enc_pkt = av_packet_alloc();
 enc_pkt->data = NULL;
 enc_pkt->size = 0;

 if (!(codecCtx->codec->capabilities & AV_CODEC_CAP_DELAY))
 return 0;

 printf("Flushing stream #%u encoder\n", vStreamIndex);
 if (avcodec_send_frame(codecCtx, 0) >= 0) {
 while (avcodec_receive_packet(codecCtx, enc_pkt) >= 0) {
 printf("success encoder 1 frame.\n");

 // parpare packet for muxing
 enc_pkt->stream_index = vStreamIndex;
 av_packet_rescale_ts(enc_pkt, codecCtx->time_base,
 fmtCtx->streams[vStreamIndex]->time_base);
 ret = av_interleaved_write_frame(fmtCtx, enc_pkt);
 if (ret < 0) {
 break;
 }
 }
 }

 av_packet_unref(enc_pkt);

 return ret;
}

int main() {
 int ret = 0;
 avdevice_register_all();

 AVFormatContext *inFmtCtx = avformat_alloc_context();
 AVCodecContext *inCodecCtx = NULL;
 const AVCodec *inCodec = NULL;
 AVPacket *inPkt = av_packet_alloc();
 AVFrame *srcFrame = av_frame_alloc();
 AVFrame *yuvFrame = av_frame_alloc();

 //打开输出文件,并填充fmtCtx数据
 AVFormatContext *outFmtCtx = avformat_alloc_context();
 const AVOutputFormat *outFmt = NULL;
 AVCodecContext *outCodecCtx = NULL;
 const AVCodec *outCodec = NULL;
 AVStream *outVStream = NULL;

 AVPacket *outPkt = av_packet_alloc();

 struct SwsContext *img_ctx = NULL;

 int inVideoStreamIndex = -1;

 do {
 /////////////解码器部分//////////////////////
 //打开摄像头
#ifdef _WIN32
 const AVInputFormat *inFmt = av_find_input_format("gdigrab");
 if (avformat_open_input(&inFmtCtx, "desktop", inFmt, NULL) < 0) {
 printf("Cannot open camera.\n");
 break;
 }
#elif __linux__
 AVInputFormat *inFmt = av_find_input_format("v4l2");
 if(avformat_open_input(&inFmtCtx,"/dev/video0",inFmt,NULL)<0){
 printf("Cannot open camera.\n");
 break;
 }
#endif

 if (avformat_find_stream_info(inFmtCtx, NULL) < 0) {
 printf("Cannot find any stream in file.\n");
 break;
 }

 for (uint32_t i = 0; i < inFmtCtx->nb_streams; i++) {
 if (inFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
 inVideoStreamIndex = i;
 break;
 }
 }
 if (inVideoStreamIndex == -1) {
 printf("Cannot find video stream in file.\n");
 break;
 }

 AVCodecParameters *inVideoCodecPara = inFmtCtx->streams[inVideoStreamIndex]->codecpar;
 if (!(inCodec = avcodec_find_decoder(inVideoCodecPara->codec_id))) {
 printf("Cannot find valid video decoder.\n");
 break;
 }
 if (!(inCodecCtx = avcodec_alloc_context3(inCodec))) {
 printf("Cannot alloc valid decode codec context.\n");
 break;
 }
 if (avcodec_parameters_to_context(inCodecCtx, inVideoCodecPara) < 0) {
 printf("Cannot initialize parameters.\n");
 break;
 }

 if (avcodec_open2(inCodecCtx, inCodec, NULL) < 0) {
 printf("Cannot open codec.\n");
 break;
 }

 img_ctx = sws_getContext(inCodecCtx->width,
 inCodecCtx->height,
 inCodecCtx->pix_fmt,
 inCodecCtx->width,
 inCodecCtx->height,
 AV_PIX_FMT_YUV420P,
 SWS_BICUBIC,
 NULL, NULL, NULL);

 int numBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
 inCodecCtx->width,
 inCodecCtx->height, 1);
 uint8_t *out_buffer = (unsigned char *) av_malloc(numBytes * sizeof(unsigned char));

 ret = av_image_fill_arrays(yuvFrame->data,
 yuvFrame->linesize,
 out_buffer,
 AV_PIX_FMT_YUV420P,
 inCodecCtx->width,
 inCodecCtx->height,
 1);
 if (ret < 0) {
 printf("Fill arrays failed.\n");
 break;
 }
 //////////////解码器部分结束/////////////////////

 //////////////编码器部分开始/////////////////////
 const char *outFile = "camera.mp4";

 if (avformat_alloc_output_context2(&outFmtCtx, NULL, "mp4", outFile) < 0) {
 printf("Cannot alloc output file context.\n");
 break;
 }
 outFmt = outFmtCtx->oformat;

 //打开输出文件
 if (avio_open(&outFmtCtx->pb, outFile, AVIO_FLAG_READ_WRITE) < 0) {
 printf("output file open failed.\n");
 break;
 }

 //创建h264视频流,并设置参数
 outVStream = avformat_new_stream(outFmtCtx, outCodec);
 if (outVStream == NULL) {
 printf("create new video stream fialed.\n");
 break;
 }
 outVStream->time_base.den = 60;
 outVStream->time_base.num = 1;

 //编码参数相关
 AVCodecParameters *outCodecPara = outFmtCtx->streams[outVStream->index]->codecpar;
 outCodecPara->codec_type = AVMEDIA_TYPE_VIDEO;
 outCodecPara->codec_id = outFmt->video_codec;
 outCodecPara->width = 1920;
 outCodecPara->height = 1080;
 outCodecPara->bit_rate = 110000;

 //查找编码器
 outCodec = avcodec_find_encoder(outFmt->video_codec);
 if (outCodec == NULL) {
 printf("Cannot find any encoder.\n");
 break;
 }

 //设置编码器内容
 outCodecCtx = avcodec_alloc_context3(outCodec);
 avcodec_parameters_to_context(outCodecCtx, outCodecPara);
 if (outCodecCtx == NULL) {
 printf("Cannot alloc output codec content.\n");
 break;
 }
 outCodecCtx->codec_id = outFmt->video_codec;
 outCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
 outCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
 outCodecCtx->width = inCodecCtx->width;
 outCodecCtx->height = inCodecCtx->height;
 outCodecCtx->time_base.num = 1;
 outCodecCtx->time_base.den = 60;
 outCodecCtx->bit_rate = 110000;
 outCodecCtx->gop_size = 10;

 if (outCodecCtx->codec_id == AV_CODEC_ID_H264) {
 outCodecCtx->qmin = 10;
 outCodecCtx->qmax = 51;
 outCodecCtx->qcompress = (float) 0.6;
 } else if (outCodecCtx->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
 outCodecCtx->max_b_frames = 2;
 } else if (outCodecCtx->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
 outCodecCtx->mb_decision = 2;
 }

 //打开编码器
 if (avcodec_open2(outCodecCtx, outCodec, NULL) < 0) {
 printf("Open encoder failed.\n");
 break;
 }
 ///////////////编码器部分结束////////////////////

 ///////////////编解码部分//////////////////////
 yuvFrame->format = outCodecCtx->pix_fmt;
 yuvFrame->width = outCodecCtx->width;
 yuvFrame->height = outCodecCtx->height;

 ret = avformat_write_header(outFmtCtx, NULL);

 int count = 0;
 while (av_read_frame(inFmtCtx, inPkt) >= 0 && count < 50) {
 if (inPkt->stream_index == inVideoStreamIndex) {
 if (avcodec_send_packet(inCodecCtx, inPkt) >= 0) {
 while ((ret = avcodec_receive_frame(inCodecCtx, srcFrame)) >= 0) {
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
 return -1;
 else if (ret < 0) {
 fprintf(stderr, "Error during decoding\n");
 exit(1);
 }
 sws_scale(img_ctx,
 (const uint8_t *const ) srcFrame->data,
 srcFrame->linesize,
 0, inCodecCtx->height,
 yuvFrame->data, yuvFrame->linesize);

 yuvFrame->pts = srcFrame->pts;
 //encode
 if (avcodec_send_frame(outCodecCtx, yuvFrame) >= 0) {
 if (avcodec_receive_packet(outCodecCtx, outPkt) >= 0) {
 printf("encode %d frame.\n", count);
 ++count;
 outPkt->stream_index = outVStream->index;
 av_packet_rescale_ts(outPkt, outCodecCtx->time_base,
 outVStream->time_base);
 outPkt->pos = -1;
 av_interleaved_write_frame(outFmtCtx, outPkt);
 av_packet_unref(outPkt);
 }
 }
#ifdef _WIN32
 Sleep(24);//延时24毫秒
#elif __linux__
 usleep(100024);
#endif
 }
 }
 av_packet_unref(inPkt);
 fflush(stdout);
 }
 }

 ret = flush_encoder(outFmtCtx, outCodecCtx, outVStream->index);
 if (ret < 0) {
 printf("flushing encoder failed.\n");
 break;
 }

 av_write_trailer(outFmtCtx);
 ////////////////编解码部分结束////////////////
 } while (0);

 ///////////内存释放部分/////////////////////////
 av_packet_free(&inPkt);
 avcodec_free_context(&inCodecCtx);
 avcodec_close(inCodecCtx);
 avformat_close_input(&inFmtCtx);
 av_frame_free(&srcFrame);
 av_frame_free(&yuvFrame);

 av_packet_free(&outPkt);
 avcodec_free_context(&outCodecCtx);
 avcodec_close(outCodecCtx);
 avformat_close_input(&outFmtCtx);

 return 0;
}

`
[gdigrab @ 00000200744161c0] Capturing whole desktop as 1920x1080x32 at (0,0)
[gdigrab @ 00000200744161c0] Stream #0: not enough frames to estimate rate; consider increasing probesize
[mpeg4 @ 0000020077990140] time_incr 28484223107072 too large
[mpeg4 @ 0000020077990140] time_incr 28484223108885 too large
[mpeg4 @ 0000020077990140] time_incr 28484223109141 too large
[mpeg4 @ 0000020077990140] time_incr 28484223109138 too large
[mpeg4 @ 0000020077990140] time_incr 28484223109359 too large
[mpeg4 @ 0000020077990140] time_incr 28484223108843 too large
[mpeg4 @ 0000020077990140] time_incr 28484223109364 too large
[mpeg4 @ 0000020077990140] time_incr 28484223109107 too large
[mpeg4 @ 0000020077990140] time_incr 28484223108890 too large
[mpeg4 @ 0000020077990140] time_incr 28484223108883 too large

例12:转换出的H.264视频在海康播放软件上显示“无效”。

你好!请教一下如题的问题。
#1实现过程:
我是摄像头拍一帧保存一帧YUV格式的图片,然后YUV图片转成.h264文件,再用ffmpeg将多个.h264文件concat成.h264视频。
#2YUV格式图片一些参数设置
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// 视频数据存储类型 V4L2_PIX_FMT_YUV420
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.width = 640;
//Images包含top和bottom field, 隔行交替,场序依赖于当前video的标准
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
帧率30。
#3 经过你的代码合成h264视频,输出信息。
root@ud710-ai:/home/unisoc/ruida/ko_camera/v4l2/h264# ffprobe -i output.h264
ffprobe version 4.1 Copyright (c) 2007-2018 the FFmpeg developers
built with gcc 7 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04)
configuration: --prefix=/usr/local/ffmpeg --enable-shared --enable-yasm --enable-libx264 --enable-gpl --enable-pthreads --extra-cflags=-I/usr/local/x264/include --extra-ldflags=-L/usr/local/x264/lib --disable-x86asm
libavutil 56. 22.100 / 56. 22.100
libavcodec 58. 35.100 / 58. 35.100
libavformat 58. 20.100 / 58. 20.100
libavdevice 58. 5.100 / 58. 5.100
libavfilter 7. 40.101 / 7. 40.101
libswscale 5. 3.100 / 5. 3.100
libswresample 3. 3.100 / 3. 3.100
libpostproc 55. 3.100 / 55. 3.100
Input #0, h264, from 'output.h264':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (High), yuv420p(progressive), 640x480, 30 fps, 30 tbr, 1200k tbn, 60 tbc

例12

你好,我使用你的代码,转换出的H.264视频在海康播放软件上显示“无效”。
YUV图片我使用的是v4l2来保存的,其中的一些参数是:
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// 视频数据存储类型 V4L2_PIX_FMT_YUV420
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.width = 640;
//Images包含top和bottom field, 隔行交替,场序依赖于当前video的标准
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
帧率30.

请问是什么原因呢?

使用opengl渲染ffpmeg解码的yuv数据,颜色发暗,色彩不够鲜艳。

对比测试08、09示例。播放同一个视频。08使用软件渲染rgb数据,09使用yuv 通过opengl渲染显示。对比发现09显示的白色发黑颜色值不够鲜艳。
播放电影不太明显,直接使用录屏软件录制视频然后播放特别明显。不知道是上面原因。
对比关键信息:
使用录屏软件,打开浏览器访问百度主页,对比网页的白色,与百度图标的红色。opengl显示的明显白色发暗黑,红色不够鲜艳。可否告知一下原因?感谢

使用opengl渲染ffpmeg解码的yuv数据,颜色发暗,色彩不够鲜艳。

使用opengl渲染ffpmeg解码的yuv数据,颜色发暗,色彩不够鲜艳。
对比测试08、09示例。播放同一个视频。08使用软件渲染rgb数据,09使用yuv 通过opengl渲染显示。对比发现09显示的白色发黑颜色值不够鲜艳。
播放电影不太明显,直接使用录屏软件录制视频然后播放特别明显。不知道是上面原因。
对比关键信息:
使用录屏软件,打开浏览器访问百度主页,对比网页的白色,与百度图标的红色。opengl显示的明显白色发暗黑,红色不够鲜艳。可否告知一下原因?感谢

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.