采集摄像头

  1. ffmpeg -f video4linux2 -s 640x480 -pixel_format yuyv422 -i /dev/video1 out.mp4 -loglevel debug

采集桌面

  1. ffmpeg 需要使能: --enable-libxcb
  2. ffmpeg -f x11grab -framerate 25 -video_size 1280*720 -i :0.0 out.mp4

采集桌面(树莓派)

ffmpeg -f x11grab -s 1280x720 -i :0.0 -f alsa -i hw:0,0 -f flv out.mp4

采集桌面&摄像头的画面,并保存为YUV420P格式

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <fstream>
  6. #include <iostream>
  7. using namespace std;
  8. extern "C"
  9. {
  10. #include <libavutil/log.h>
  11. #include <libavcodec/avcodec.h>
  12. #include <libavformat/avformat.h>
  13. #include <libavdevice/avdevice.h>
  14. #include <libswscale/swscale.h>
  15. #include <libavutil/imgutils.h>
  16. }
  17. #define YUV420P_DUMP
  18. int main(int argc, char *argv[])
  19. {
  20. av_log_set_level(AV_LOG_INFO);
  21. if(argc < 3|| strlen(argv[1]) == 0 || strlen(argv[2]) == 0 )
  22. {
  23. av_log(nullptr, AV_LOG_ERROR, "usage: ./FFrecorder format filename.\n");
  24. av_log(nullptr, AV_LOG_ERROR, "for camera: ./FFrecorder video4linux2 /dev/video0.\n");
  25. av_log(nullptr, AV_LOG_ERROR, "for screen: ./FFrecorder x11grab :0.0 .\n");
  26. return -1;
  27. }
  28. avcodec_register_all();
  29. avdevice_register_all();
  30. AVInputFormat *pInputFmt;
  31. AVDictionary *pOptions =nullptr;
  32. AVFormatContext *pFmtCtx = nullptr;
  33. AVCodecContext *pCodecCtx =nullptr;
  34. AVCodec *pCodec =nullptr;
  35. struct SwsContext *pSwsCtx=nullptr;
  36. AVPacket *pPacket = nullptr;
  37. AVFrame *pFrame = nullptr;
  38. AVFrame *pYUVFrame = nullptr;
  39. int vieoStreamIndex = -1;
  40. int retValue = 0;
  41. int bGotFrame = 0;
  42. int frameCnt = 10;
  43. pInputFmt = av_find_input_format(argv[1]);
  44. if(pInputFmt == nullptr)
  45. {
  46. av_log(nullptr, AV_LOG_ERROR, "cant not find input format.\n");
  47. return -2;
  48. }
  49. if(strcmp(argv[1],"video4linux2") == 0)
  50. {
  51. av_dict_set(&pOptions, "video_size", "1280*720", AV_DICT_MATCH_CASE);
  52. av_dict_set(&pOptions, "framerate", "10", AV_DICT_MATCH_CASE);
  53. }
  54. else if (strcmp(argv[1],"x11grab") == 0)
  55. {
  56. av_dict_set(&pOptions, "video_size", "1280*720", AV_DICT_MATCH_CASE);
  57. av_dict_set(&pOptions, "framerate", "10", AV_DICT_MATCH_CASE);
  58. }
  59. if (avformat_open_input ( &pFmtCtx, argv[2], pInputFmt , &pOptions) < 0){
  60. av_log(nullptr, AV_LOG_ERROR, "cant not open input file.\n");
  61. return -3;
  62. }
  63. /* print device information*/
  64. av_dump_format(pFmtCtx, 0, argv[2], 0);
  65. if(avformat_find_stream_info(pFmtCtx, nullptr)<0)
  66. {
  67. av_log(nullptr, AV_LOG_ERROR, "cant not find stream information.\n");
  68. return -4;
  69. }
  70. vieoStreamIndex = -1;
  71. for(int iter=0; iter < static_cast<int>(pFmtCtx->nb_streams); iter++)
  72. {
  73. if(pFmtCtx->streams[iter]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
  74. {
  75. vieoStreamIndex=iter;
  76. break;
  77. }
  78. }
  79. if(vieoStreamIndex == -1){
  80. av_log(nullptr, AV_LOG_ERROR, "cant not find a video stream.\n");
  81. return -5;
  82. }
  83. pCodecCtx=pFmtCtx->streams[vieoStreamIndex]->codec;
  84. pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  85. if(pCodec==nullptr){
  86. av_log(nullptr, AV_LOG_ERROR, "cant not find codec.\n");
  87. return -6;
  88. }
  89. av_log(NULL, AV_LOG_INFO, "using codec:%s.\n", pCodec->name);
  90. if(avcodec_open2(pCodecCtx, pCodec, nullptr)<0)
  91. {
  92. av_log(nullptr, AV_LOG_ERROR, "cant not open codec.\n");
  93. return -7;
  94. }
  95. pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
  96. pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P,
  97. SWS_BICUBIC, nullptr, nullptr, nullptr);
  98. #ifdef YUV420P_DUMP
  99. ofstream out_image("video.yuv", ios::binary);
  100. if (!out_image.is_open())
  101. {
  102. av_log(nullptr, AV_LOG_ERROR, "Failed to save yuv video: %s\n", "video.yuv");
  103. return -8;
  104. }
  105. #endif
  106. pPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
  107. pFrame = av_frame_alloc();
  108. pYUVFrame = av_frame_alloc();
  109. uint8_t *pYUVFrameBuffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1));
  110. av_image_fill_arrays(pYUVFrame->data, pYUVFrame->linesize, pYUVFrameBuffer,
  111. AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
  112. pYUVFrame->format = AV_PIX_FMT_YUV420P;
  113. while(av_read_frame(pFmtCtx, pPacket)>=0)
  114. {
  115. if(pPacket->stream_index == vieoStreamIndex)
  116. {
  117. retValue = avcodec_decode_video2(pCodecCtx, pFrame, &bGotFrame, pPacket);
  118. if(retValue < 0){
  119. av_log(nullptr, AV_LOG_ERROR, "decode a frame error.\n");
  120. break;
  121. }
  122. if(bGotFrame)
  123. {
  124. av_log(nullptr, AV_LOG_INFO, "get a frame.\n");
  125. sws_scale(pSwsCtx, static_cast<const uint8_t *const *>(pFrame->data), pFrame->linesize, 0,
  126. pCodecCtx->height, pYUVFrame->data, pYUVFrame->linesize);
  127. //av_log(nullptr, AV_LOG_INFO, "pFrame->format %d.\n", pFrame->format );
  128. //av_log(nullptr, AV_LOG_INFO, "pYUVFrame->format %d.\n", pYUVFrame->format );
  129. if (static_cast<AVPixelFormat>(pYUVFrame->format) == AV_PIX_FMT_YUV420P)
  130. {
  131. #ifdef YUV420P_DUMP
  132. int y_size = pCodecCtx->width * pCodecCtx->height;
  133. out_image.write((char *)pYUVFrame->data[0], y_size);
  134. out_image.write((char *)pYUVFrame->data[1], y_size / 4);
  135. out_image.write((char *)pYUVFrame->data[2], y_size / 4);
  136. //av_log(nullptr, AV_LOG_INFO, "write a frame.\n");
  137. #endif
  138. }
  139. frameCnt--;
  140. }
  141. if(frameCnt == 0)
  142. {
  143. break;
  144. }
  145. }
  146. }
  147. #ifdef YUV420P_DUMP
  148. out_image.close();
  149. #endif
  150. sws_freeContext(pSwsCtx);
  151. av_free(pYUVFrameBuffer);
  152. av_free(pPacket);
  153. av_free(pYUVFrame);
  154. av_free(pFrame);
  155. avcodec_close(pCodecCtx);
  156. avformat_close_input(&pFmtCtx);
  157. av_free(pFmtCtx);
  158. return 0;
  159. }
  160. ######################################
  161. #
  162. ######################################
  163. #source file
  164. #源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件
  165. SOURCE := $(wildcard *.c) $(wildcard *.cpp)
  166. OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
  167. #target you can change test to what you want
  168. #目标文件名,输入任意你想要的执行文件名
  169. TARGET := FFrecorder
  170. #compile and lib parameter
  171. #编译参数
  172. CXX := g++
  173. LIBS := -L /usr/local/lib -lavformat -lavutil -lavdevice -lavcodec -lswresample -lavfilter -lswscale -pthread
  174. LDFLAGS :=
  175. DEFINES :=
  176. INCLUDE := -I.
  177. CFLAGS := -g -Wall -O3 -std=c11 $(DEFINES) $(INCLUDE)
  178. CXXFLAGS:= -g -Wall -O3 -std=c++11 $(DEFINES) $(INCLUDE)
  179. #i think you should do anything here
  180. #下面的基本上不需要做任何改动了
  181. .PHONY : everything objs clean veryclean rebuild
  182. everything : $(TARGET)
  183. all : $(TARGET)
  184. objs : $(OBJS)
  185. rebuild: veryclean everything
  186. clean :
  187. rm -fr *.so
  188. rm -fr *.o
  189. veryclean : clean
  190. rm -fr $(TARGET)
  191. $(TARGET) : $(OBJS)
  192. $(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)

FFMPEG(一) 从V4L2捕获摄像头数据
FFmpeg接口-AVDictionary的使用介绍和源码分析