采集摄像头
ffmpeg -f video4linux2 -s 640x480 -pixel_format yuyv422 -i /dev/video1 out.mp4 -loglevel debug
采集桌面
ffmpeg 需要使能: --enable-libxcbffmpeg -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格式
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <fstream>#include <iostream>using namespace std;extern "C"{#include <libavutil/log.h>#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavdevice/avdevice.h>#include <libswscale/swscale.h>#include <libavutil/imgutils.h>}#define YUV420P_DUMPint main(int argc, char *argv[]){av_log_set_level(AV_LOG_INFO);if(argc < 3|| strlen(argv[1]) == 0 || strlen(argv[2]) == 0 ){av_log(nullptr, AV_LOG_ERROR, "usage: ./FFrecorder format filename.\n");av_log(nullptr, AV_LOG_ERROR, "for camera: ./FFrecorder video4linux2 /dev/video0.\n");av_log(nullptr, AV_LOG_ERROR, "for screen: ./FFrecorder x11grab :0.0 .\n");return -1;}avcodec_register_all();avdevice_register_all();AVInputFormat *pInputFmt;AVDictionary *pOptions =nullptr;AVFormatContext *pFmtCtx = nullptr;AVCodecContext *pCodecCtx =nullptr;AVCodec *pCodec =nullptr;struct SwsContext *pSwsCtx=nullptr;AVPacket *pPacket = nullptr;AVFrame *pFrame = nullptr;AVFrame *pYUVFrame = nullptr;int vieoStreamIndex = -1;int retValue = 0;int bGotFrame = 0;int frameCnt = 10;pInputFmt = av_find_input_format(argv[1]);if(pInputFmt == nullptr){av_log(nullptr, AV_LOG_ERROR, "cant not find input format.\n");return -2;}if(strcmp(argv[1],"video4linux2") == 0){av_dict_set(&pOptions, "video_size", "1280*720", AV_DICT_MATCH_CASE);av_dict_set(&pOptions, "framerate", "10", AV_DICT_MATCH_CASE);}else if (strcmp(argv[1],"x11grab") == 0){av_dict_set(&pOptions, "video_size", "1280*720", AV_DICT_MATCH_CASE);av_dict_set(&pOptions, "framerate", "10", AV_DICT_MATCH_CASE);}if (avformat_open_input ( &pFmtCtx, argv[2], pInputFmt , &pOptions) < 0){av_log(nullptr, AV_LOG_ERROR, "cant not open input file.\n");return -3;}/* print device information*/av_dump_format(pFmtCtx, 0, argv[2], 0);if(avformat_find_stream_info(pFmtCtx, nullptr)<0){av_log(nullptr, AV_LOG_ERROR, "cant not find stream information.\n");return -4;}vieoStreamIndex = -1;for(int iter=0; iter < static_cast<int>(pFmtCtx->nb_streams); iter++){if(pFmtCtx->streams[iter]->codec->codec_type==AVMEDIA_TYPE_VIDEO){vieoStreamIndex=iter;break;}}if(vieoStreamIndex == -1){av_log(nullptr, AV_LOG_ERROR, "cant not find a video stream.\n");return -5;}pCodecCtx=pFmtCtx->streams[vieoStreamIndex]->codec;pCodec=avcodec_find_decoder(pCodecCtx->codec_id);if(pCodec==nullptr){av_log(nullptr, AV_LOG_ERROR, "cant not find codec.\n");return -6;}av_log(NULL, AV_LOG_INFO, "using codec:%s.\n", pCodec->name);if(avcodec_open2(pCodecCtx, pCodec, nullptr)<0){av_log(nullptr, AV_LOG_ERROR, "cant not open codec.\n");return -7;}pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P,SWS_BICUBIC, nullptr, nullptr, nullptr);#ifdef YUV420P_DUMPofstream out_image("video.yuv", ios::binary);if (!out_image.is_open()){av_log(nullptr, AV_LOG_ERROR, "Failed to save yuv video: %s\n", "video.yuv");return -8;}#endifpPacket = (AVPacket *)av_malloc(sizeof(AVPacket));pFrame = av_frame_alloc();pYUVFrame = av_frame_alloc();uint8_t *pYUVFrameBuffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1));av_image_fill_arrays(pYUVFrame->data, pYUVFrame->linesize, pYUVFrameBuffer,AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);pYUVFrame->format = AV_PIX_FMT_YUV420P;while(av_read_frame(pFmtCtx, pPacket)>=0){if(pPacket->stream_index == vieoStreamIndex){retValue = avcodec_decode_video2(pCodecCtx, pFrame, &bGotFrame, pPacket);if(retValue < 0){av_log(nullptr, AV_LOG_ERROR, "decode a frame error.\n");break;}if(bGotFrame){av_log(nullptr, AV_LOG_INFO, "get a frame.\n");sws_scale(pSwsCtx, static_cast<const uint8_t *const *>(pFrame->data), pFrame->linesize, 0,pCodecCtx->height, pYUVFrame->data, pYUVFrame->linesize);//av_log(nullptr, AV_LOG_INFO, "pFrame->format %d.\n", pFrame->format );//av_log(nullptr, AV_LOG_INFO, "pYUVFrame->format %d.\n", pYUVFrame->format );if (static_cast<AVPixelFormat>(pYUVFrame->format) == AV_PIX_FMT_YUV420P){#ifdef YUV420P_DUMPint y_size = pCodecCtx->width * pCodecCtx->height;out_image.write((char *)pYUVFrame->data[0], y_size);out_image.write((char *)pYUVFrame->data[1], y_size / 4);out_image.write((char *)pYUVFrame->data[2], y_size / 4);//av_log(nullptr, AV_LOG_INFO, "write a frame.\n");#endif}frameCnt--;}if(frameCnt == 0){break;}}}#ifdef YUV420P_DUMPout_image.close();#endifsws_freeContext(pSwsCtx);av_free(pYUVFrameBuffer);av_free(pPacket);av_free(pYUVFrame);av_free(pFrame);avcodec_close(pCodecCtx);avformat_close_input(&pFmtCtx);av_free(pFmtCtx);return 0;}##############################################################################source file#源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件SOURCE := $(wildcard *.c) $(wildcard *.cpp)OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))#target you can change test to what you want#目标文件名,输入任意你想要的执行文件名TARGET := FFrecorder#compile and lib parameter#编译参数CXX := g++LIBS := -L /usr/local/lib -lavformat -lavutil -lavdevice -lavcodec -lswresample -lavfilter -lswscale -pthreadLDFLAGS :=DEFINES :=INCLUDE := -I.CFLAGS := -g -Wall -O3 -std=c11 $(DEFINES) $(INCLUDE)CXXFLAGS:= -g -Wall -O3 -std=c++11 $(DEFINES) $(INCLUDE)#i think you should do anything here#下面的基本上不需要做任何改动了.PHONY : everything objs clean veryclean rebuildeverything : $(TARGET)all : $(TARGET)objs : $(OBJS)rebuild: veryclean everythingclean :rm -fr *.sorm -fr *.overyclean : cleanrm -fr $(TARGET)$(TARGET) : $(OBJS)$(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
