├── LICENSE ├── README.md ├── bin └── ScreenRecorder ├── compile.sh ├── include └── ScreenRecorder.h ├── media ├── sample_screen_shot.png └── sample_video.mp4 └── src ├── ScreenRecorder.cpp └── main.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Abdullah Farweez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # screen-recorder-ffmpeg-cpp 2 | 3 | ## DESCRIPTION 4 | **screen-recorder-ffmpeg-cpp** is an application to record a desktop (x11). 5 | 6 | Screen recorder applications was developed using C++ FFMPEG library. Screen recorder can able to capture the screen as video and store it in advanced codec of Mpeg4 and mp4 formats. 7 | 8 | keep track and fork **master branch** [an updated branch] 9 | 10 | > **LICENSE : MIT License** 11 | 12 | > **Note:** 13 | 14 | > - To use this application , libavcodec , libavformat , x11grab , ffmpeg libraries must be installed in ubuntu based computer. check [here][1] ffmpeg for installation procedure. 15 | > - To stop the application , toggle Ctrl+C . 16 | 17 | ---------- 18 | 19 | Below is the sample screen shot of video screen recorder. click the below to view the resultant video of the Screen recorder applications.. 20 | 21 | [![Watch the video](https://github.com/abdullahfarwees/screen-recorder-ffmpeg-cpp/blob/master/media/sample_screen_shot.png)](https://youtu.be/a31bBY3HuxE) 22 | 23 | [1]:https://trac.ffmpeg.org/wiki/CompilationGuide 24 | 25 | ---------- 26 | 27 | **If you like this project, STAR it, FORK it on Github!.** 28 | -------------------------------------------------------------------------------- /bin/ScreenRecorder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdullahfarwees/screen-recorder-ffmpeg-cpp/32b7420ed69a0f8d829825e7478f07e7de9502dc/bin/ScreenRecorder -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | g++ -Wno-format-zero-length -Wno-write-strings -L/home/abdullah/ffmpeg_build/lib/ -L/usr/lib/x86_64-linux-gnu/ -I/home/abdullah/ffmpeg_build/include/ -o bin/ScreenRecorder src/main.cpp src/ScreenRecorder.cpp -lavdevice -lavfilter -lswscale -lavformat -lavcodec -lavutil -lswresample -lm -lva -lpthread -lvorbis -lvpx -lopus -lz -lpostproc -ldl -lfdk-aac -lmp3lame -lvorbisenc -lvorbisfile -lx264 -ltheora -lx265 -ltheoraenc -ltheoradec -ldl -lrt -lbz2 -lasound -lSDL -lSDLmain -lSDL_ttf -lfreetype -lass -llzma -lftgl -lperl -lcrypto -lxcb -lxcb-shm -lxcb-xfixes -lao -lxcb-shape -lfftw3 2 | 3 | 4 | -------------------------------------------------------------------------------- /include/ScreenRecorder.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREENRECORDER_H 2 | #define SCREENRECORDER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define __STDC_CONSTANT_MACROS 13 | 14 | //FFMPEG LIBRARIES 15 | extern "C" 16 | { 17 | #include "libavcodec/avcodec.h" 18 | #include "libavcodec/avfft.h" 19 | 20 | #include "libavdevice/avdevice.h" 21 | 22 | #include "libavfilter/avfilter.h" 23 | #include "libavfilter/avfiltergraph.h" 24 | #include "libavfilter/buffersink.h" 25 | #include "libavfilter/buffersrc.h" 26 | 27 | #include "libavformat/avformat.h" 28 | #include "libavformat/avio.h" 29 | 30 | // libav resample 31 | 32 | #include "libavutil/opt.h" 33 | #include "libavutil/common.h" 34 | #include "libavutil/channel_layout.h" 35 | #include "libavutil/imgutils.h" 36 | #include "libavutil/mathematics.h" 37 | #include "libavutil/samplefmt.h" 38 | #include "libavutil/time.h" 39 | #include "libavutil/opt.h" 40 | #include "libavutil/pixdesc.h" 41 | #include "libavutil/file.h" 42 | 43 | // lib swresample 44 | 45 | #include "libswscale/swscale.h" 46 | 47 | } 48 | 49 | 50 | 51 | class ScreenRecorder 52 | { 53 | private: 54 | AVInputFormat *pAVInputFormat; 55 | AVOutputFormat *output_format; 56 | 57 | AVCodecContext *pAVCodecContext; 58 | 59 | AVFormatContext *pAVFormatContext; 60 | 61 | AVFrame *pAVFrame; 62 | AVFrame *outFrame; 63 | 64 | AVCodec *pAVCodec; 65 | AVCodec *outAVCodec; 66 | 67 | AVPacket *pAVPacket; 68 | 69 | AVDictionary *options; 70 | 71 | AVOutputFormat *outAVOutputFormat; 72 | AVFormatContext *outAVFormatContext; 73 | AVCodecContext *outAVCodecContext; 74 | 75 | AVStream *video_st; 76 | AVFrame *outAVFrame; 77 | 78 | const char *dev_name; 79 | const char *output_file; 80 | 81 | double video_pts; 82 | 83 | int out_size; 84 | int codec_id; 85 | int value; 86 | int VideoStreamIndx; 87 | 88 | public: 89 | 90 | ScreenRecorder(); 91 | ~ScreenRecorder(); 92 | 93 | /* function to initiate communication with display library */ 94 | int openCamera(); 95 | int init_outputfile(); 96 | int CaptureVideoFrames(); 97 | 98 | }; 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /media/sample_screen_shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdullahfarwees/screen-recorder-ffmpeg-cpp/32b7420ed69a0f8d829825e7478f07e7de9502dc/media/sample_screen_shot.png -------------------------------------------------------------------------------- /media/sample_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdullahfarwees/screen-recorder-ffmpeg-cpp/32b7420ed69a0f8d829825e7478f07e7de9502dc/media/sample_video.mp4 -------------------------------------------------------------------------------- /src/ScreenRecorder.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/ScreenRecorder.h" 2 | 3 | using namespace std; 4 | 5 | /* initialize the resources*/ 6 | ScreenRecorder::ScreenRecorder() 7 | { 8 | 9 | av_register_all(); 10 | avcodec_register_all(); 11 | avdevice_register_all(); 12 | cout<<"\nall required functions are registered successfully"; 13 | } 14 | 15 | /* uninitialize the resources */ 16 | ScreenRecorder::~ScreenRecorder() 17 | { 18 | 19 | avformat_close_input(&pAVFormatContext); 20 | if( !pAVFormatContext ) 21 | { 22 | cout<<"\nfile closed sucessfully"; 23 | } 24 | else 25 | { 26 | cout<<"\nunable to close the file"; 27 | exit(1); 28 | } 29 | 30 | avformat_free_context(pAVFormatContext); 31 | if( !pAVFormatContext ) 32 | { 33 | cout<<"\navformat free successfully"; 34 | } 35 | else 36 | { 37 | cout<<"\nunable to free avformat context"; 38 | exit(1); 39 | } 40 | 41 | } 42 | 43 | /* function to capture and store data in frames by allocating required memory and auto deallocating the memory. */ 44 | int ScreenRecorder::CaptureVideoFrames() 45 | { 46 | int flag; 47 | int frameFinished;//when you decode a single packet, you still don't have information enough to have a frame [depending on the type of codec, some of them //you do], when you decode a GROUP of packets that represents a frame, then you have a picture! that's why frameFinished will let //you know you decoded enough to have a frame. 48 | 49 | int frame_index = 0; 50 | value = 0; 51 | 52 | pAVPacket = (AVPacket *)av_malloc(sizeof(AVPacket)); 53 | av_init_packet(pAVPacket); 54 | 55 | pAVFrame = av_frame_alloc(); 56 | if( !pAVFrame ) 57 | { 58 | cout<<"\nunable to release the avframe resources"; 59 | exit(1); 60 | } 61 | 62 | outFrame = av_frame_alloc();//Allocate an AVFrame and set its fields to default values. 63 | if( !outFrame ) 64 | { 65 | cout<<"\nunable to release the avframe resources for outframe"; 66 | exit(1); 67 | } 68 | 69 | int video_outbuf_size; 70 | int nbytes = av_image_get_buffer_size(outAVCodecContext->pix_fmt,outAVCodecContext->width,outAVCodecContext->height,32); 71 | uint8_t *video_outbuf = (uint8_t*)av_malloc(nbytes); 72 | if( video_outbuf == NULL ) 73 | { 74 | cout<<"\nunable to allocate memory"; 75 | exit(1); 76 | } 77 | 78 | // Setup the data pointers and linesizes based on the specified image parameters and the provided array. 79 | value = av_image_fill_arrays( outFrame->data, outFrame->linesize, video_outbuf , AV_PIX_FMT_YUV420P, outAVCodecContext->width,outAVCodecContext->height,1 ); // returns : the size in bytes required for src 80 | if(value < 0) 81 | { 82 | cout<<"\nerror in filling image array"; 83 | } 84 | 85 | SwsContext* swsCtx_ ; 86 | 87 | // Allocate and return swsContext. 88 | // a pointer to an allocated context, or NULL in case of error 89 | // Deprecated : Use sws_getCachedContext() instead. 90 | swsCtx_ = sws_getContext(pAVCodecContext->width, 91 | pAVCodecContext->height, 92 | pAVCodecContext->pix_fmt, 93 | outAVCodecContext->width, 94 | outAVCodecContext->height, 95 | outAVCodecContext->pix_fmt, 96 | SWS_BICUBIC, NULL, NULL, NULL); 97 | 98 | 99 | int ii = 0; 100 | int no_frames = 100; 101 | cout<<"\nenter No. of frames to capture : "; 102 | cin>>no_frames; 103 | 104 | AVPacket outPacket; 105 | int j = 0; 106 | 107 | int got_picture; 108 | 109 | while( av_read_frame( pAVFormatContext , pAVPacket ) >= 0 ) 110 | { 111 | if( ii++ == no_frames )break; 112 | if(pAVPacket->stream_index == VideoStreamIndx) 113 | { 114 | value = avcodec_decode_video2( pAVCodecContext , pAVFrame , &frameFinished , pAVPacket ); 115 | if( value < 0) 116 | { 117 | cout<<"unable to decode video"; 118 | } 119 | 120 | if(frameFinished)// Frame successfully decoded :) 121 | { 122 | sws_scale(swsCtx_, pAVFrame->data, pAVFrame->linesize,0, pAVCodecContext->height, outFrame->data,outFrame->linesize); 123 | av_init_packet(&outPacket); 124 | outPacket.data = NULL; // packet data will be allocated by the encoder 125 | outPacket.size = 0; 126 | 127 | avcodec_encode_video2(outAVCodecContext , &outPacket ,outFrame , &got_picture); 128 | 129 | if(got_picture) 130 | { 131 | if(outPacket.pts != AV_NOPTS_VALUE) 132 | outPacket.pts = av_rescale_q(outPacket.pts, video_st->codec->time_base, video_st->time_base); 133 | if(outPacket.dts != AV_NOPTS_VALUE) 134 | outPacket.dts = av_rescale_q(outPacket.dts, video_st->codec->time_base, video_st->time_base); 135 | 136 | printf("Write frame %3d (size= %2d)\n", j++, outPacket.size/1000); 137 | if(av_write_frame(outAVFormatContext , &outPacket) != 0) 138 | { 139 | cout<<"\nerror in writing video frame"; 140 | } 141 | 142 | av_packet_unref(&outPacket); 143 | } // got_picture 144 | 145 | av_packet_unref(&outPacket); 146 | } // frameFinished 147 | 148 | } 149 | }// End of while-loop 150 | 151 | value = av_write_trailer(outAVFormatContext); 152 | if( value < 0) 153 | { 154 | cout<<"\nerror in writing av trailer"; 155 | exit(1); 156 | } 157 | 158 | 159 | //THIS WAS ADDED LATER 160 | av_free(video_outbuf); 161 | 162 | } 163 | 164 | /* establishing the connection between camera or screen through its respective folder */ 165 | int ScreenRecorder::openCamera() 166 | { 167 | 168 | value = 0; 169 | options = NULL; 170 | pAVFormatContext = NULL; 171 | 172 | pAVFormatContext = avformat_alloc_context();//Allocate an AVFormatContext. 173 | /* 174 | 175 | X11 video input device. 176 | To enable this input device during configuration you need libxcb installed on your system. It will be automatically detected during configuration. 177 | This device allows one to capture a region of an X11 display. 178 | refer : https://www.ffmpeg.org/ffmpeg-devices.html#x11grab 179 | */ 180 | /* current below is for screen recording. to connect with camera use v4l2 as a input parameter for av_find_input_format */ 181 | pAVInputFormat = av_find_input_format("x11grab"); 182 | value = avformat_open_input(&pAVFormatContext, ":0.0+10,250", pAVInputFormat, NULL); 183 | if(value != 0) 184 | { 185 | cout<<"\nerror in opening input device"; 186 | exit(1); 187 | } 188 | 189 | /* set frame per second */ 190 | value = av_dict_set( &options,"framerate","30",0 ); 191 | if(value < 0) 192 | { 193 | cout<<"\nerror in setting dictionary value"; 194 | exit(1); 195 | } 196 | 197 | value = av_dict_set( &options, "preset", "medium", 0 ); 198 | if(value < 0) 199 | { 200 | cout<<"\nerror in setting preset values"; 201 | exit(1); 202 | } 203 | 204 | // value = avformat_find_stream_info(pAVFormatContext,NULL); 205 | if(value < 0) 206 | { 207 | cout<<"\nunable to find the stream information"; 208 | exit(1); 209 | } 210 | 211 | VideoStreamIndx = -1; 212 | 213 | /* find the first video stream index . Also there is an API available to do the below operations */ 214 | for(int i = 0; i < pAVFormatContext->nb_streams; i++ ) // find video stream posistion/index. 215 | { 216 | if( pAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) 217 | { 218 | VideoStreamIndx = i; 219 | break; 220 | } 221 | 222 | } 223 | 224 | if( VideoStreamIndx == -1) 225 | { 226 | cout<<"\nunable to find the video stream index. (-1)"; 227 | exit(1); 228 | } 229 | 230 | // assign pAVFormatContext to VideoStreamIndx 231 | pAVCodecContext = pAVFormatContext->streams[VideoStreamIndx]->codec; 232 | 233 | pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id); 234 | if( pAVCodec == NULL ) 235 | { 236 | cout<<"\nunable to find the decoder"; 237 | exit(1); 238 | } 239 | 240 | value = avcodec_open2(pAVCodecContext , pAVCodec , NULL);//Initialize the AVCodecContext to use the given AVCodec. 241 | if( value < 0 ) 242 | { 243 | cout<<"\nunable to open the av codec"; 244 | exit(1); 245 | } 246 | } 247 | 248 | /* initialize the video output file and its properties */ 249 | int ScreenRecorder::init_outputfile() 250 | { 251 | outAVFormatContext = NULL; 252 | value = 0; 253 | output_file = "../media/output.mp4"; 254 | 255 | avformat_alloc_output_context2(&outAVFormatContext, NULL, NULL, output_file); 256 | if (!outAVFormatContext) 257 | { 258 | cout<<"\nerror in allocating av format output context"; 259 | exit(1); 260 | } 261 | 262 | /* Returns the output format in the list of registered output formats which best matches the provided parameters, or returns NULL if there is no match. */ 263 | output_format = av_guess_format(NULL, output_file ,NULL); 264 | if( !output_format ) 265 | { 266 | cout<<"\nerror in guessing the video format. try with correct format"; 267 | exit(1); 268 | } 269 | 270 | video_st = avformat_new_stream(outAVFormatContext ,NULL); 271 | if( !video_st ) 272 | { 273 | cout<<"\nerror in creating a av format new stream"; 274 | exit(1); 275 | } 276 | 277 | outAVCodecContext = avcodec_alloc_context3(outAVCodec); 278 | if( !outAVCodecContext ) 279 | { 280 | cout<<"\nerror in allocating the codec contexts"; 281 | exit(1); 282 | } 283 | 284 | /* set property of the video file */ 285 | outAVCodecContext = video_st->codec; 286 | outAVCodecContext->codec_id = AV_CODEC_ID_MPEG4;// AV_CODEC_ID_MPEG4; // AV_CODEC_ID_H264 // AV_CODEC_ID_MPEG1VIDEO 287 | outAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO; 288 | outAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P; 289 | outAVCodecContext->bit_rate = 400000; // 2500000 290 | outAVCodecContext->width = 1920; 291 | outAVCodecContext->height = 1080; 292 | outAVCodecContext->gop_size = 3; 293 | outAVCodecContext->max_b_frames = 2; 294 | outAVCodecContext->time_base.num = 1; 295 | outAVCodecContext->time_base.den = 30; // 15fps 296 | 297 | if (codec_id == AV_CODEC_ID_H264) 298 | { 299 | av_opt_set(outAVCodecContext->priv_data, "preset", "slow", 0); 300 | } 301 | 302 | outAVCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4); 303 | if( !outAVCodec ) 304 | { 305 | cout<<"\nerror in finding the av codecs. try again with correct codec"; 306 | exit(1); 307 | } 308 | 309 | /* Some container formats (like MP4) require global headers to be present 310 | Mark the encoder so that it behaves accordingly. */ 311 | 312 | if ( outAVFormatContext->oformat->flags & AVFMT_GLOBALHEADER) 313 | { 314 | outAVCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; 315 | } 316 | 317 | value = avcodec_open2(outAVCodecContext, outAVCodec, NULL); 318 | if( value < 0) 319 | { 320 | cout<<"\nerror in opening the avcodec"; 321 | exit(1); 322 | } 323 | 324 | /* create empty video file */ 325 | if ( !(outAVFormatContext->flags & AVFMT_NOFILE) ) 326 | { 327 | if( avio_open2(&outAVFormatContext->pb , output_file , AVIO_FLAG_WRITE ,NULL, NULL) < 0 ) 328 | { 329 | cout<<"\nerror in creating the video file"; 330 | exit(1); 331 | } 332 | } 333 | 334 | if(!outAVFormatContext->nb_streams) 335 | { 336 | cout<<"\noutput file dose not contain any stream"; 337 | exit(1); 338 | } 339 | 340 | /* imp: mp4 container or some advanced container file required header information*/ 341 | value = avformat_write_header(outAVFormatContext , &options); 342 | if(value < 0) 343 | { 344 | cout<<"\nerror in writing the header context"; 345 | exit(1); 346 | } 347 | 348 | /* 349 | // uncomment here to view the complete video file informations 350 | cout<<"\n\nOutput file information :\n\n"; 351 | av_dump_format(outAVFormatContext , 0 ,output_file ,1); 352 | */ 353 | } 354 | 355 | 356 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../include/ScreenRecorder.h" 3 | 4 | using namespace std; 5 | 6 | /* driver function to run the application */ 7 | int main() 8 | { 9 | ScreenRecorder screen_record; 10 | 11 | screen_record.openCamera(); 12 | screen_record.init_outputfile(); 13 | screen_record.CaptureVideoFrames(); 14 | 15 | cout<<"\nprogram executed successfully\n"; 16 | 17 | return 0; 18 | } 19 | --------------------------------------------------------------------------------