├── 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 | [](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 |
--------------------------------------------------------------------------------