1 /* CODE ADAPATED FOR ARDRONE NAVIGATION FROM :
3 * Libavformat API example: Output a media file in any supported
4 * libavformat format. The default codecs are used.
6 * Copyright (c) 2003 Fabrice Bellard
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include <generated_custom.h>
29 /*#ifndef USE_FFMPEG_RECORDER
30 #define USE_FFMPEG_RECORDER
33 #ifdef USE_FFMPEG_RECORDER
35 /* From FFMPEG example */
41 #include <libavformat/avformat.h>
42 #include <libswscale/swscale.h>
43 #include <libavfilter/avfilter.h>
44 #include <libavutil/avutil.h>
45 #include <libavcodec/avcodec.h>
46 #include <libavcodec/opt.h>
50 #include <sys/types.h>
56 /* Should be in avutil.h but Ubuntu 10.04 package is too old
57 * http://cekirdek.pardus.org.tr/~ismail/ffmpeg-docs/libavutil_2avutil_8h-source.html
59 #if LIBAVUTIL_VERSION_MAJOR < 50
60 #define AV_PKT_FLAG_KEY 0x0001
62 AVMEDIA_TYPE_UNKNOWN = -1,
66 AVMEDIA_TYPE_SUBTITLE,
67 AVMEDIA_TYPE_ATTACHMENT,
77 #include <sys/timeb.h>
78 #include <Winsock2.h> // for timeval structure
80 int gettimeofday (struct timeval *tp, void *tz)
82 struct _timeb timebuffer;
84 tp->tv_sec = (long)timebuffer.time;
85 tp->tv_usec = (long)timebuffer.millitm * 1000;
90 #include <VP_Os/vp_os_malloc.h>
91 #include <VP_Api/vp_api_picture.h>
94 #include <ardrone_tool/Video/video_stage_ffmpeg_recorder.h>
96 /*#ifdef USE_VIDEO_YUV
97 #define VIDEO_FILE_EXTENSION "yuv"
99 #define VIDEO_FILE_EXTENSION "y"
101 #define VIDEO_TIMESTAMPS_FILE_EXTENSION "time.txt"
103 #ifndef VIDEO_FILE_DEFAULT_PATH
105 #define VIDEO_FILE_DEFAULT_PATH "/data/video"
107 #define VIDEO_FILE_DEFAULT_PATH "."
111 #define VIDEO_FILE_DEFAULT_PATH "."
113 /*- LibAVFormat variables */
114 const char *filename;
121 #define STREAM_FRAME_RATE (60)
122 #define STREAM_BIT_RATE_KBITS 1600
123 #define STREAM_PIX_FMT PIX_FMT_YUV420P /* default pix_fmt */
125 static int sws_flags = SWS_BICUBIC;
127 AVFrame *picture_to_encode=NULL, *tmp_picture=NULL;
128 uint8_t *video_outbuf=NULL;
129 int frame_count=0, video_outbuf_size=0;
132 const vp_api_stage_funcs_t video_ffmpeg_recorder_funcs = {
133 (vp_api_stage_handle_msg_t) video_stage_ffmpeg_recorder_handle,
134 (vp_api_stage_open_t) video_stage_ffmpeg_recorder_open,
135 (vp_api_stage_transform_t) video_stage_ffmpeg_recorder_transform,
136 (vp_api_stage_close_t) video_stage_ffmpeg_recorder_close
139 char video_filename_ffmpeg[VIDEO_FILENAME_LENGTH];
145 unsigned long long int timestamp_us;
150 /******************************************************************************************************************************************/
152 void create_video_file(const char*filename,int width,int height)
154 /* auto detect the output format from the name. default is
156 //fmt = av_guess_format(NULL, filename, NULL);
158 #if (LIBAVFORMAT_VERSION_INT>=AV_VERSION_INT(52,81,0))
159 #define libavformat_guess_format av_guess_format
161 #define libavformat_guess_format guess_format
164 fmt = libavformat_guess_format(NULL, filename, NULL);
167 printf("Could not deduce output format from file extension: using MPEG.\n");
168 //fmt = av_guess_format("mpeg", NULL, NULL);
169 fmt = libavformat_guess_format("mpeg", NULL, NULL);
172 fprintf(stderr, "Could not find suitable output format\n");
176 /* allocate the output media context */
177 oc = avformat_alloc_context();
179 fprintf(stderr, "Memory error\n");
183 snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
185 /* add the audio and video streams using the default format codecs
186 and initialize the codecs */
189 if (fmt->video_codec != CODEC_ID_NONE) {
190 video_st = add_video_stream(oc, fmt->video_codec,width,height);
193 /* set the output parameters (must be done even if no
195 if (av_set_parameters(oc, NULL) < 0) {
196 fprintf(stderr, "Invalid output format parameters\n");
200 dump_format(oc, 0, filename, 1);
202 /* now that all the parameters are set, we can open the audio and
203 video codecs and allocate the necessary encode buffers */
205 open_video(oc, video_st);
207 /* open the output file, if needed */
208 if (!(fmt->flags & AVFMT_NOFILE)) {
209 if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {
210 fprintf(stderr, "Could not open '%s'\n", filename);
215 /* write the stream header, if any */
220 void close_video_file()
222 /* write the trailer, if any. the trailer must be written
223 * before you close the CodecContexts open when you wrote the
224 * header; otherwise write_trailer may try to use memory that
225 * was freed on av_codec_close() */
226 av_write_trailer(oc);
228 /* close each codec */
230 close_video(oc, video_st);
232 /* free the streams */
233 for(i = 0; i < oc->nb_streams; i++) {
234 av_freep(&oc->streams[i]->codec);
235 av_freep(&oc->streams[i]);
238 if (!(fmt->flags & AVFMT_NOFILE)) {
239 /* close the output file */
243 /* free the stream */
250 /**************************************************************/
255 /* add a video output stream */
256 AVStream *add_video_stream(AVFormatContext *oc, enum CodecID codec_id, int width, int height)
261 st = av_new_stream(oc, 0);
263 fprintf(stderr, "Could not alloc stream\n");
268 c->codec_id = codec_id;
269 c->codec_type = AVMEDIA_TYPE_VIDEO;
271 /* put sample parameters */
272 c->bit_rate = (STREAM_BIT_RATE_KBITS)*1000;
273 /* resolution must be a multiple of two */
276 /* time base: this is the fundamental unit of time (in seconds) in terms
277 of which frame timestamps are represented. for fixed-fps content,
278 timebase should be 1/framerate and timestamp increments should be
280 c->time_base.den = STREAM_FRAME_RATE;
281 c->time_base.num = 1;
282 c->gop_size = 12; /* emit one intra frame every twelve frames at most */
283 c->pix_fmt = STREAM_PIX_FMT;
284 if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
285 /* just for testing, we also add B frames */
288 if (c->codec_id == CODEC_ID_MPEG1VIDEO){
289 /* Needed to avoid using macroblocks in which some coeffs overflow.
290 This does not happen with normal video, it just happens here as
291 the motion of the chroma plane does not match the luma plane. */
294 // some formats want stream headers to be separate
295 if(oc->oformat->flags & AVFMT_GLOBALHEADER)
296 c->flags |= CODEC_FLAG_GLOBAL_HEADER;
301 AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height)
304 uint8_t *picture_buf;
307 picture = avcodec_alloc_frame();
310 size = avpicture_get_size(pix_fmt, width, height);
311 picture_buf = av_malloc(size);
316 avpicture_fill((AVPicture *)picture, picture_buf,
317 pix_fmt, width, height);
321 void open_video(AVFormatContext *oc, AVStream *st)
328 /* find the video encoder */
329 codec = avcodec_find_encoder(c->codec_id);
331 fprintf(stderr, "codec not found\n");
336 if (avcodec_open(c, codec) < 0) {
337 fprintf(stderr, "could not open codec\n");
342 if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
343 /* allocate output buffer */
344 /* XXX: API change will be done */
345 /* buffers passed into lav* can be allocated any way you prefer,
346 as long as they're aligned enough for the architecture, and
347 they're freed appropriately (such as using av_free for buffers
348 allocated with av_malloc) */
349 video_outbuf_size = 200000;
350 video_outbuf = av_malloc(video_outbuf_size);
353 /* allocate the encoded raw picture */
354 picture_to_encode = avcodec_alloc_frame();
355 //alloc_picture(c->pix_fmt, c->width, c->height);
357 fprintf(stderr, "Could not allocate picture\n");
361 /* if the output format is not YUV420P, then a temporary YUV420P
362 picture is needed too. It is then converted to the required
365 if (c->pix_fmt != PIX_FMT_YUV420P) {
366 tmp_picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height);
368 fprintf(stderr, "Could not allocate temporary picture\n");
375 void write_video_frame(AVFormatContext *oc, AVStream *st)
379 static struct SwsContext *img_convert_ctx;
381 //printf("Here0 \n");
385 if (c->pix_fmt != PIX_FMT_YUV420P) {
386 /* as we only generate a YUV420P picture, we must convert it
387 to the codec pixel format if needed */
388 if (img_convert_ctx == NULL) {
390 #if (LIBSWSCALE_VERSION_INT<AV_VERSION_INT(0,12,0))
391 img_convert_ctx = sws_getContext(c->width, c->height,
395 sws_flags, NULL, NULL, NULL);
397 img_convert_ctx = sws_alloc_context();
399 if (img_convert_ctx == NULL) {
400 fprintf(stderr, "Cannot initialize the conversion context\n");
404 /* see http://permalink.gmane.org/gmane.comp.video.ffmpeg.devel/118362 */
405 /* see http://ffmpeg-users.933282.n4.nabble.com/Documentation-for-sws-init-context-td2956723.html */
407 av_set_int(img_convert_ctx, "srcw", c->width);
408 av_set_int(img_convert_ctx, "srch", c->height);
410 av_set_int(img_convert_ctx, "dstw", c->width);
411 av_set_int(img_convert_ctx, "dsth", c->height);
413 av_set_int(img_convert_ctx, "src_format", PIX_FMT_YUV420P);
414 av_set_int(img_convert_ctx, "dst_format", c->pix_fmt);
416 av_set_int(img_convert_ctx, "param0", 0);
417 av_set_int(img_convert_ctx, "param1", 0);
419 av_set_int(img_convert_ctx, "flags", sws_flags);
421 sws_init_context(img_convert_ctx,NULL,NULL);
425 sws_scale(img_convert_ctx, (const uint8_t* const *)tmp_picture->data,
426 tmp_picture->linesize,
427 0, c->height, picture_to_encode->data, picture_to_encode->linesize);
433 if (oc->oformat->flags & AVFMT_RAWPICTURE) {
434 /* raw video case. The API will change slightly in the near
437 av_init_packet(&pkt);
439 pkt.flags |= AV_PKT_FLAG_KEY;
440 pkt.stream_index= st->index;
441 pkt.data= (uint8_t *)picture_to_encode;
442 pkt.size= sizeof(AVPicture);
444 ret = av_interleaved_write_frame(oc, &pkt);
446 /* encode the image */
447 //printf("Here1 \n");
448 out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture_to_encode);
449 /* if zero size, it means the image was buffered */
452 av_init_packet(&pkt);
454 if (c->coded_frame->pts != AV_NOPTS_VALUE)
455 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
456 if(c->coded_frame->key_frame)
457 pkt.flags |= AV_PKT_FLAG_KEY;
458 pkt.stream_index= st->index;
459 pkt.data= video_outbuf;
462 /* write the compressed frame in the media file */
463 ret = av_interleaved_write_frame(oc, &pkt);
469 fprintf(stderr, "Error while writing video frame\n");
475 void close_video(AVFormatContext *oc, AVStream *st)
477 avcodec_close(st->codec);
478 //av_free(picture->data[0]);
479 av_free(picture_to_encode);
480 picture_to_encode = NULL;
482 av_free(tmp_picture->data[0]);
483 av_free(tmp_picture);
486 av_free(video_outbuf);
490 /******************************************************************************************************************************************/
492 video_stage_ffmpeg_recorder_handle (video_stage_ffmpeg_recorder_config_t * cfg, PIPELINE_MSG msg_id, void *callback, void *param)
494 //return (VP_SUCCESS);
496 printf("FFMPEG recorder message handler.\n");
499 case PIPELINE_MSG_START:
502 if(cfg->startRec==VIDEO_RECORD_STOP)
503 cfg->startRec=VIDEO_RECORD_HOLD;
505 cfg->startRec=VIDEO_RECORD_STOP;
515 /******************************************************************************************************************************************/
516 C_RESULT video_stage_ffmpeg_recorder_open(video_stage_ffmpeg_recorder_config_t *cfg)
520 previous_frame.width = previous_frame.height = 0;
521 previous_frame.buffer = NULL;
522 previous_frame.timestamp_us = 0;
523 previous_frame.frame_number =0;
525 cfg->startRec=VIDEO_RECORD_STOP;
527 /* initialize libavcodec, and register all codecs and formats */
534 /******************************************************************************************************************************************/
535 C_RESULT video_stage_ffmpeg_recorder_transform(video_stage_ffmpeg_recorder_config_t *cfg, vp_api_io_data_t *in, vp_api_io_data_t *out)
540 long long int current_timestamp_us;
541 static long long int first_frame_timestamp_us=0;
542 static int frame_counter=0;
545 static int flag_video_file_open=0;
547 vp_os_mutex_lock( &out->lock );
548 vp_api_picture_t* picture = (vp_api_picture_t *) in->buffers;
550 gettimeofday(&tv,NULL);
552 temptime = (time_t)tv.tv_sec;
553 atm = localtime(&temptime); //atm = localtime(&tv.tv_sec);
555 current_timestamp_us = tv.tv_sec *1000000 + tv.tv_usec;
558 if( out->status == VP_API_STATUS_INIT )
561 out->indexBuffer = 0;
562 out->lineSize = NULL;
563 //out->buffers = (int8_t **) vp_os_malloc( sizeof(int8_t *) );
566 out->size = in->size;
567 out->status = in->status;
568 out->buffers = in->buffers;
570 if( in->status == VP_API_STATUS_ENDED ) {
571 out->status = in->status;
573 else if(in->status == VP_API_STATUS_STILL_RUNNING) {
574 out->status = VP_API_STATUS_PROCESSING;
577 out->status = in->status;
582 if(cfg->startRec==VIDEO_RECORD_HOLD)
584 /* Create a new video file */
586 sprintf(video_filename_ffmpeg, "%s/video_%04d%02d%02d_%02d%02d%02d_w%i_h%i.mp4",
587 VIDEO_FILE_DEFAULT_PATH,
588 atm->tm_year+1900, atm->tm_mon+1, atm->tm_mday,
589 atm->tm_hour, atm->tm_min, atm->tm_sec,
593 create_video_file(video_filename_ffmpeg, picture->width,picture->height);
594 flag_video_file_open=1;
596 cfg->startRec=VIDEO_RECORD_START;
598 first_frame_timestamp_us = current_timestamp_us;
602 if( out->size > 0 && out->status == VP_API_STATUS_PROCESSING && cfg->startRec==VIDEO_RECORD_START)
604 frame_size = ( previous_frame.width * previous_frame.height )*3/2;
606 /* Send the previous frame to FFMPEG */
607 if (previous_frame.buffer!=NULL)
609 /* Compute the number of frames to store to achieve 60 FPS
610 * This should be computed using the timestamp of the first frame
611 * to avoid error accumulation.
613 int current_frame_number = (current_timestamp_us - first_frame_timestamp_us) / 16666;
614 int nb_frames_to_write = current_frame_number - previous_frame.frame_number;
616 if (picture_to_encode!=NULL){
617 picture_to_encode->data[0] = picture_to_encode->base[0] = picture->y_buf;
618 picture_to_encode->data[1] = picture_to_encode->base[1] = picture->cb_buf;
619 picture_to_encode->data[2] = picture_to_encode->base[2] = picture->cr_buf;
621 picture_to_encode->linesize[0] = picture->width;
622 picture_to_encode->linesize[1] = picture->width/2;
623 picture_to_encode->linesize[2] = picture->width/2;
626 for (i=0;i<nb_frames_to_write;i++)
628 //printf("Storing %i frames\n",nb_frames_to_write);
629 write_video_frame(oc, video_st);
632 /* Pass infos to next iteration */
633 previous_frame.frame_number = current_frame_number;
636 /* Create a buffer to hold the current frame */
639 if (previous_frame.buffer!=NULL && (previous_frame.width!=picture->width || previous_frame.height!=picture->height))
641 vp_os_free(previous_frame.buffer);
642 previous_frame.buffer=NULL;
644 if (previous_frame.buffer==NULL)
646 previous_frame.width = picture->width;
647 previous_frame.height = picture->height;
648 frame_size = ( previous_frame.width * previous_frame.height )*3/2;
649 printf("Allocating previous frame.\n");
650 previous_frame.buffer=vp_os_malloc( frame_size );
653 /* Copy the current frame in a buffer so it can be encoded at next stage call */
654 if (previous_frame.buffer!=NULL)
656 char * dest = previous_frame.buffer;
657 int size = picture->width*picture->height;
658 vp_os_memcpy(dest,picture->y_buf,size);
662 vp_os_memcpy(dest,picture->cb_buf,size);
665 vp_os_memcpy(dest,picture->cr_buf,size);
673 if(cfg->startRec==VIDEO_RECORD_STOP && flag_video_file_open)
676 flag_video_file_open=0;
680 vp_os_mutex_unlock( &out->lock );
687 /******************************************************************************************************************************************/
690 C_RESULT video_stage_ffmpeg_recorder_close(video_stage_ffmpeg_recorder_config_t *cfg)
692 if( cfg->fp != NULL )