YARP  2.3.70.1
Yet Another Robot Platform
FfmpegWriter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006 RobotCub Consortium
3  * Authors: Paul Fitzpatrick
4  * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
5  *
6  * Most of this file is from the output_example.c of ffmpeg -
7  * copyright/copypolicy statement follows --
8  *
9  */
10 
11 /*
12  * Libavformat API example: Output a media file in any supported
13  * libavformat format. The default codecs are used.
14  *
15  * Copyright (c) 2003 Fabrice Bellard
16  *
17  * Permission is hereby granted, free of charge, to any person obtaining a copy
18  * of this software and associated documentation files (the "Software"), to deal
19  * in the Software without restriction, including without limitation the rights
20  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21  * copies of the Software, and to permit persons to whom the Software is
22  * furnished to do so, subject to the following conditions:
23  *
24  * The above copyright notice and this permission notice shall be included in
25  * all copies or substantial portions of the Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33  * THE SOFTWARE.
34  */
35 
36 
37 #include "FfmpegWriter.h"
38 #include <yarp/os/all.h>
39 #include <yarp/sig/all.h>
40 
41 #include "ffmpeg_api.h"
42 
43 #include <cstdio>
44 
45 using namespace yarp::os;
46 using namespace yarp::dev;
47 using namespace yarp::sig;
48 using namespace yarp::sig::file;
49 
50 #define DBG if (0)
51 
52 //#define OMIT_AUDIO
53 
54 #include <cstdlib>
55 #include <cstdio>
56 #include <cstring>
57 #include <cmath>
58 
59 #ifndef M_PI
60 #define M_PI 3.1415926535897931
61 #endif
62 
63 //#include <ffmpeg/avformat.h>
64 //#include <ffmpeg/avcodec.h>
65 
66 #define STREAM_FRAME_RATE 25 /* 25 images/s */
67 #define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
68 #define STREAM_PIX_WORK AV_PIX_FMT_RGB24
69 
70 /**************************************************************/
71 /* audio output */
72 
73 float t, tincr, tincr2;
74 
75 int16_t *samples;
79 
80 uint8_t *audio_outbuf;
83 
84 /*
85  * add an audio output stream
86  */
87 static AVStream *add_audio_stream(AVFormatContext *oc, CodecID codec_id)
88 {
89  AVCodecContext *c;
90  AVStream *st;
91 
92  st = av_new_stream(oc, 1);
93  if (!st) {
94  fprintf(stderr, "Could not alloc stream\n");
95  ::exit(1);
96  }
97 
98  c = st->codec;
99  c->codec_id = codec_id;
100  c->codec_type = CODEC_TYPE_AUDIO;
101 
102  /* put sample parameters */
103  c->bit_rate = 64000;
104  c->sample_rate = 44100;
105  c->channels = 2;
106  return st;
107 }
108 
109 static void open_audio(AVFormatContext *oc, AVStream *st)
110 {
111  printf("Opening audio stream\n");
112  AVCodecContext *c;
113  AVCodec *codec;
114 
115  c = st->codec;
116 
117  /* find the audio encoder */
118  codec = avcodec_find_encoder(c->codec_id);
119  if (!codec) {
120  fprintf(stderr, "audio codec not found\n");
121  ::exit(1);
122  }
123 
124  /* open it */
125  if (avcodec_open2(c, codec, NULL) < 0) {
126  fprintf(stderr, "could not open codec\n");
127  ::exit(1);
128  }
129 
130  /* init signal generator */
131  t = 0;
132  tincr = 2 * M_PI * 110.0 / c->sample_rate;
133  /* increment frequency by 110 Hz per second */
134  tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
135 
136  audio_outbuf_size = 10000;
137  audio_outbuf = (uint8_t*)av_malloc(audio_outbuf_size);
138 
139  /* ugly hack for PCM codecs (will be removed ASAP with new PCM
140  support to compute the input frame size in samples */
141  if (c->frame_size <= 1) {
143  switch(st->codec->codec_id) {
144  case CODEC_ID_PCM_S16LE:
145  case CODEC_ID_PCM_S16BE:
146  case CODEC_ID_PCM_U16LE:
147  case CODEC_ID_PCM_U16BE:
149  break;
150  default:
151  break;
152  }
153  } else {
154  audio_input_frame_size = c->frame_size;
155  }
157  samples_at = 0;
158  samples_channels = c->channels;
159  samples = (int16_t*)av_malloc(samples_size*2*samples_channels);
160 
161 
162  printf("FRAME SIZE is %d / samples size is %d\n",
163  c->frame_size,
164  samples_size);
165  ::exit(1);
166 }
167 
168 /* prepare a 16 bit dummy audio frame of 'frame_size' samples and
169  'nb_channels' channels */
170 static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
171 {
172  int j, i, v;
173  int16_t *q;
174 
175  q = samples;
176  for(j=0;j<frame_size;j++) {
177  v = (int)(sin(t) * 10000);
178  for(i = 0; i < nb_channels; i++)
179  *q++ = v;
180  t += tincr;
181  tincr += tincr2;
182  }
183 }
184 
185 #ifdef USE_AUDIO4
186 static void make_audio_frame(AVCodecContext *c, AVFrame * &frame,
187  void *&samples) {
188  frame = av_frame_alloc();
189  if (!frame) {
190  fprintf(stderr, "Could not allocate audio frame\n");
191  ::exit(1);
192  }
193  frame->nb_samples = c->frame_size;
194  frame->format = c->sample_fmt;
195  frame->channel_layout = c->channel_layout;
196  int buffer_size = av_samples_get_buffer_size(NULL, c->channels,
197  c->frame_size,
198  c->sample_fmt, 0);
199  if (buffer_size < 0) {
200  fprintf(stderr, "Could not get sample buffer size\n");
201  ::exit(1);
202  }
203  samples = av_malloc(buffer_size);
204  if (!samples) {
205  fprintf(stderr, "Could not allocate %d bytes for samples buffer\n",
206  buffer_size);
207  ::exit(1);
208  }
209  /* setup the data pointers in the AVFrame */
210  int ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
211  (const uint8_t*)samples, buffer_size, 0);
212  if (ret < 0) {
213  fprintf(stderr, "Could not setup audio frame\n");
214  ::exit(1);
215  }
216 }
217 #endif
218 
219 static void write_audio_frame(AVFormatContext *oc, AVStream *st)
220 {
221  AVCodecContext *c;
222  AVPacket pkt;
223  av_init_packet(&pkt);
224 
225  c = st->codec;
226 
228 
229 #ifdef USE_AUDIO4
230  AVFrame *frame;
231  void *samples;
232  make_audio_frame(c,frame,samples);
233  AVPacket tmp;
234  int got_packet = 0;
235  av_init_packet(&tmp);
236  tmp.data = audio_outbuf;
237  tmp.size = audio_outbuf_size;
238  pkt.size = avcodec_encode_audio2(c, &tmp, frame, &got_packet);
239  if (tmp.side_data_elems > 0) {
240  for (int i = 0; i < tmp.side_data_elems; i++) {
241  av_free(tmp.side_data[i].data);
242  }
243  av_freep(&tmp.side_data);
244  tmp.side_data_elems = 0;
245  }
246  av_freep(&samples);
247  av_frame_free(&frame);
248 #else
249  pkt.size= avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples);
250 #endif
251 
252  pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
253  pkt.flags |= PKT_FLAG_KEY;
254  pkt.stream_index= st->index;
255  pkt.data= audio_outbuf;
256 
257  /* write the compressed frame in the media file */
258  if (av_write_frame(oc, &pkt) != 0) {
259  fprintf(stderr, "Error while writing audio frame\n");
260  ::exit(1);
261  } else {
262  printf("Wrote some audio\n");
263  }
264 }
265 
266 static void write_audio_frame(AVFormatContext *oc, AVStream *st, Sound& snd)
267 {
268  printf("Preparing to write audio (%d left over)\n", samples_at);
269  AVCodecContext *c;
270  int key = 1;
271 
272  c = st->codec;
273 
274  int at = 0;
275  while (at<snd.getSamples()) {
276 
277  int avail = samples_size - samples_at;
278  int remain = snd.getSamples() - at;
279  int chan = snd.getChannels();
280  if (remain<avail) { avail = remain; }
281  for (int i=0; i<avail; i++) {
282  int offset = samples_at*samples_channels;
283  for (int j=0; j<samples_channels; j++) {
284  samples[offset+j] = snd.get(at,j%chan);
285  }
286  samples_at++;
287  at++;
288  }
289  avail = samples_size - samples_at;
290 
291  if (avail==0) {
292  AVPacket pkt;
293  av_init_packet(&pkt);
294 
295 
296 #ifdef USE_AUDIO4
297  AVFrame *frame;
298  void *samples;
299  make_audio_frame(c,frame,samples);
300  AVPacket tmp;
301  int got_packet = 0;
302  av_init_packet(&tmp);
303  tmp.data = audio_outbuf;
304  tmp.size = audio_outbuf_size;
305  pkt.size = avcodec_encode_audio2(c, &tmp, frame, &got_packet);
306  if (tmp.side_data_elems > 0) {
307  for (int i = 0; i < tmp.side_data_elems; i++) {
308  av_free(tmp.side_data[i].data);
309  }
310  av_freep(&tmp.side_data);
311  tmp.side_data_elems = 0;
312  }
313  av_freep(&samples);
314  av_frame_free(&frame);
315 #else
316  pkt.size= avcodec_encode_audio(c,
317  audio_outbuf,
319  samples);
320 #endif
321 
322  pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base,
323  st->time_base);
324  pkt.dts = pkt.pts;
325  //printf("(%d)", pkt.size);
326  if (key) {
327  pkt.flags |= PKT_FLAG_KEY;
328  key = 0;
329  }
330  pkt.stream_index= st->index;
331  pkt.data = audio_outbuf;
332  pkt.duration = 0;
333 
334 
335  /* write the compressed frame in the media file */
336  printf("+");
337  fflush(stdout);
338  if (av_write_frame(oc, &pkt) != 0) {
339  fprintf(stderr, "Error while writing audio frame\n");
340  ::exit(1);
341  } else {
342  printf(".");
343  }
344  samples_at = 0;
345  }
346  }
347  printf(" wrote audio\n");
348 }
349 
350 static void close_audio(AVFormatContext *oc, AVStream *st)
351 {
352  avcodec_close(st->codec);
353 
354  av_free(samples);
355  av_free(audio_outbuf);
356 }
357 
358 /**************************************************************/
359 /* video output */
360 
361 
362 /* add a video output stream */
363 static AVStream *add_video_stream(AVFormatContext *oc, CodecID codec_id,
364  int w, int h, int framerate)
365 {
366  DBG printf("Video stream %dx%d\n", w, h);
367 
368  AVCodecContext *c;
369  AVStream *st;
370 
371  st = av_new_stream(oc, 0);
372  if (!st) {
373  fprintf(stderr, "Could not alloc stream\n");
374  ::exit(1);
375  }
376 
377  c = st->codec;
378  c->codec_id = codec_id;
379  c->codec_type = CODEC_TYPE_VIDEO;
380 
381  /* put sample parameters */
382  c->bit_rate = 400000;
383  /* resolution must be a multiple of two */
384  c->width = w;
385  c->height = h;
386  /* time base: this is the fundamental unit of time (in seconds) in terms
387  of which frame timestamps are represented. for fixed-fps content,
388  timebase should be 1/framerate and timestamp increments should be
389  identically 1. */
390  c->time_base.den = framerate;
391  c->time_base.num = 1;
392  c->gop_size = 12; /* emit one intra frame every twelve frames at most */
393  c->pix_fmt = STREAM_PIX_FMT;
394  if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
395  /* just for testing, we also add B frames */
396  c->max_b_frames = 2;
397  }
398  if (c->codec_id == CODEC_ID_MPEG1VIDEO){
399  /* needed to avoid using macroblocks in which some coeffs overflow
400  this doesnt happen with normal video, it just happens here as the
401  motion of the chroma plane doesnt match the luma plane */
402  c->mb_decision=2;
403  }
404  // some formats want stream headers to be seperate
405  if(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp"))
406  c->flags |= CODEC_FLAG_GLOBAL_HEADER;
407 
408 
409  return st;
410 }
411 
412 static AVFrame *alloc_picture(int pix_fmt, int width, int height)
413 {
414  AVFrame *picture;
415  uint8_t *picture_buf;
416  int size;
417 
418  picture = YARP_avcodec_alloc_frame();
419  if (!picture)
420  return NULL;
421  size = avpicture_get_size((AVPixelFormat)pix_fmt, width, height);
422  picture_buf = (uint8_t*)av_malloc(size);
423  if (!picture_buf) {
424  av_free(picture);
425  return NULL;
426  }
427  avpicture_fill((AVPicture *)picture, picture_buf,
428  (AVPixelFormat)pix_fmt, width, height);
429  return picture;
430 }
431 
432 void FfmpegWriter::open_video(AVFormatContext *oc, AVStream *st)
433 {
434  printf("Opening video stream\n");
435  AVCodec *codec;
436  AVCodecContext *c;
437 
438  c = st->codec;
439 
440  /* find the video encoder */
441  codec = avcodec_find_encoder(c->codec_id);
442  if (!codec) {
443  fprintf(stderr, "video codec not found\n");
444  ::exit(1);
445  }
446 
447  /* open the codec */
448  if (avcodec_open2(c, codec, NULL) < 0) {
449  fprintf(stderr, "could not open codec\n");
450  ::exit(1);
451  }
452 
453  video_outbuf = NULL;
454  if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
455  /* allocate output buffer */
456  /* XXX: API change will be done */
457  /* buffers passed into lav* can be allocated any way you prefer,
458  as long as they're aligned enough for the architecture, and
459  they're freed appropriately (such as using av_free for buffers
460  allocated with av_malloc) */
461  video_outbuf_size = 200000;
462  video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
463  }
464 
465  /* allocate the encoded raw picture */
466  picture = alloc_picture(c->pix_fmt, c->width, c->height);
467  if (!picture) {
468  fprintf(stderr, "Could not allocate picture\n");
469  ::exit(1);
470  }
471 
472  /* if the output format is not YUV420P, then a temporary YUV420P
473  picture is needed too. It is then converted to the required
474  output format */
475  tmp_picture = NULL;
476  if (c->pix_fmt != AV_PIX_FMT_RGB24) {
477  tmp_picture = alloc_picture(AV_PIX_FMT_RGB24, c->width, c->height);
478  if (!tmp_picture) {
479  fprintf(stderr, "Could not allocate temporary picture\n");
480  ::exit(1);
481  } else {
482  DBG printf("Allocated AV_PIX_FMT_RGB24 image of dimensions %dx%d\n",
483  c->width, c->height);
484  }
485  }
486 
487  DBG printf("Video stream opened\n");
488 }
489 
490 static void fill_rgb_image(AVFrame *pict, int frame_index, int width,
491  int height, ImageOf<PixelRgb>& img)
492 {
493  int x, y;
494 
495  for(y=0;y<height;y++) {
496  for(x=0;x<width;x++) {
497  int base = y*(width*3);
498  pict->data[0][base + x*3] = img.safePixel(x,y).r;
499  pict->data[0][base +x*3+1] = img.safePixel(x,y).g;
500  pict->data[0][base +x*3+2] = img.safePixel(x,y).b;
501  }
502  }
503 }
504 
505 
506 void FfmpegWriter::write_video_frame(AVFormatContext *oc, AVStream *st,
507  ImageOf<PixelRgb>& img)
508 {
509  DBG printf("Writing video stream\n");
510 
511  int out_size, ret;
512  AVCodecContext *c;
513 
514  c = st->codec;
515 
516  if (c->pix_fmt != AV_PIX_FMT_RGB24) {
517  DBG printf("Converting to AV_PIX_FMT_RGB24\n");
518  fill_rgb_image(tmp_picture, frame_count, c->width, c->height, img);
519  DBG printf("Converting to AV_PIX_FMT_RGB24 (stable_img_convert)\n");
520  stable_img_convert((AVPicture *)picture, c->pix_fmt,
521  (AVPicture *)tmp_picture, AV_PIX_FMT_RGB24,
522  c->width, c->height);
523  DBG printf("Converted to AV_PIX_FMT_RGB24\n");
524  } else {
525  fill_rgb_image(picture, frame_count, c->width, c->height, img);
526  }
527 
528 
529  if (oc->oformat->flags & AVFMT_RAWPICTURE) {
530  /* raw video case. The API will change slightly in the near
531  futur for that */
532  AVPacket pkt;
533  av_init_packet(&pkt);
534 
535  pkt.flags |= PKT_FLAG_KEY;
536  pkt.stream_index= st->index;
537  pkt.data= (uint8_t *)picture;
538  pkt.size= sizeof(AVPicture);
539 
540  ret = av_write_frame(oc, &pkt);
541  } else {
542  /* encode the image */
543 #ifdef USE_AUDIO4
544  AVPacket tmp;
545  int got_packet = 0;
546  av_init_packet(&tmp);
547  tmp.data = video_outbuf;
548  tmp.size = video_outbuf_size;
549  out_size = avcodec_encode_video2(c, &tmp, picture, &got_packet);
550  if (tmp.side_data_elems > 0) {
551  for (int i = 0; i < tmp.side_data_elems; i++) {
552  av_free(tmp.side_data[i].data);
553  }
554  av_freep(&tmp.side_data);
555  tmp.side_data_elems = 0;
556  }
557 #else
558  out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
559 #endif
560  /* if zero size, it means the image was buffered */
561  if (out_size > 0) {
562  AVPacket pkt;
563  av_init_packet(&pkt);
564 
565  pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
566  if(c->coded_frame->key_frame)
567  pkt.flags |= PKT_FLAG_KEY;
568  pkt.stream_index= st->index;
569  pkt.data= video_outbuf;
570  pkt.size= out_size;
571 
572  /*
573  static int x = 0;
574  printf("%ld / %ld : %ld / %ld --> %d\n",
575  (long int) c->time_base.num,
576  (long int) c->time_base.den,
577  (long int) st->time_base.num,
578  (long int) st->time_base.den,
579  x);
580  pkt.pts = x;
581  x++;
582  */
583 
584  /* write the compressed frame in the media file */
585  ret = av_write_frame(oc, &pkt);
586  } else {
587  ret = 0;
588  }
589  }
590  if (ret != 0) {
591  fprintf(stderr, "Error while writing video frame\n");
592  ::exit(1);
593  }
594  frame_count++;
595 }
596 
597 void FfmpegWriter::close_video(AVFormatContext *oc, AVStream *st)
598 {
599  avcodec_close(st->codec);
600  av_free(picture->data[0]);
601  av_free(picture);
602  if (tmp_picture) {
603  av_free(tmp_picture->data[0]);
604  av_free(tmp_picture);
605  }
606  av_free(video_outbuf);
607 }
608 
609 
610 
611 
612 /**************************************************************/
613 /* YARP adaptation */
614 
615 bool FfmpegWriter::open(yarp::os::Searchable & config) {
616 // printf("ffmpeg libavcodec version number %d.%d.%d\n", LIBAVCODEC_VERSION_MAJOR,
617 // LIBAVCODEC_VERSION_MINOR,
618 // LIBAVCODEC_VERSION_MICRO);
619 
620  ready = false;
621  savedConfig.fromString(config.toString());
622 
623  // open if possible, if not will do it later
624  return delayedOpen(config);
625 }
626 
627 
628 bool FfmpegWriter::delayedOpen(yarp::os::Searchable & config) {
629  //printf("DELAYED OPEN %s\n", config.toString().c_str());
630 
631  int w = config.check("width",Value(0),
632  "width of image (must be even)").asInt();
633  int h = config.check("height",Value(0),
634  "height of image (must be even)").asInt();
635  int framerate = config.check("framerate",Value(30),
636  "baseline images per second").asInt();
637 
638  int sample_rate = 0;
639  int channels = 0;
640  bool audio = config.check("audio","should audio be included");
641  if (audio) {
642  sample_rate = config.check("sample_rate",Value(44100),
643  "audio samples per second").asInt();
644  channels = config.check("channels",Value(1),
645  "audio samples per second").asInt();
646  }
647 
648  filename = config.check("out",Value("movie.avi"),
649  "name of movie to write").asString();
650 
651  delayed = false;
652  if (w<=0||h<=0) {
653  delayed = true;
654  return true;
655  }
656  ready = true;
657 
658  /* initialize libavcodec, and register all codecs and formats */
659  av_register_all();
660 
661  /* auto detect the output format from the name. default is
662  mpeg. */
663  fmt = guess_format(NULL, filename.c_str(), NULL);
664  if (!fmt) {
665  printf("Could not deduce output format from file extension: using MPEG.\n");
666  fmt = guess_format("mpeg", NULL, NULL);
667  }
668  if (!fmt) {
669  fprintf(stderr, "Could not find suitable output format\n");
670  ::exit(1);
671  }
672 
673  /* allocate the output media context */
675  if (!oc) {
676  fprintf(stderr, "Memory error\n");
677  ::exit(1);
678  }
679  oc->oformat = fmt;
680  snprintf(oc->filename, sizeof(oc->filename), "%s", filename.c_str());
681 
682  /* add the audio and video streams using the default format codecs
683  and initialize the codecs */
684  video_st = NULL;
685  audio_st = NULL;
686  if (fmt->video_codec != CODEC_ID_NONE) {
687  video_st = add_video_stream(oc, fmt->video_codec, w, h, framerate);
688  }
689 
690 #ifndef OMIT_AUDIO
691  if (audio) {
692  printf("Adding audio %dx%d\n", sample_rate, channels);
693  if (fmt->audio_codec != CODEC_ID_NONE) {
694  audio_st = add_audio_stream(oc, fmt->audio_codec);
695  if (audio_st!=NULL) {
696  AVCodecContext *c = audio_st->codec;
697  c->sample_rate = sample_rate;
698  c->channels = channels;
699  } else {
700  printf("Failed to add audio\n");
701  }
702  } else {
703  printf("No audio codec available\n");
704  }
705  } else {
706  printf("Skipping audio\n");
707  }
708 #endif
709 
710  /* set the output parameters (must be done even if no
711  parameters). */
712 #ifndef AV_NO_SET_PARAMETERS
713  if (av_set_parameters(oc, NULL) < 0) {
714  fprintf(stderr, "Invalid output format parameters\n");
715  ::exit(1);
716  }
717 #endif
718 
719  YARP_dump_format(oc, 0, filename.c_str(), 1);
720 
721  /* now that all the parameters are set, we can open the audio and
722  video codecs and allocate the necessary encode buffers */
723  if (video_st) {
724  open_video(oc, video_st);
725  }
726  if (audio_st) {
727  open_audio(oc, audio_st);
728  }
729 
730  /* open the output file, if needed */
731  if (!(fmt->flags & AVFMT_NOFILE)) {
732  if (url_fopen(&oc->pb, filename.c_str(), URL_WRONLY) < 0) {
733  fprintf(stderr, "Could not open '%s'\n", filename.c_str());
734  ::exit(1);
735  }
736  }
737 
738  /* write the stream header, if any */
739  av_write_header(oc);
740 
741  return true;
742 }
743 
744 bool FfmpegWriter::close() {
745  if (!isOk()) { return false; }
746 
747  /* close each codec */
748  if (video_st)
749  close_video(oc, video_st);
750  if (audio_st)
751  close_audio(oc, audio_st);
752 
753  /* write the trailer, if any */
754  av_write_trailer(oc);
755 
756  /* free the streams */
757  for(unsigned int i = 0; i < oc->nb_streams; i++) {
758  av_freep(&oc->streams[i]->codec);
759  av_freep(&oc->streams[i]);
760  }
761 
762  if (!(fmt->flags & AVFMT_NOFILE)) {
763  /* close the output file */
764  url_fclose(oc->pb);
765  }
766 
767  /* free the stream */
768  av_free(oc);
769 
770  printf("Closed media file %s\n", filename.c_str());
771 
772  return true;
773 }
774 
775 bool FfmpegWriter::putImage(yarp::sig::ImageOf<yarp::sig::PixelRgb> & image) {
776  if (delayed) {
777  savedConfig.put("width",Value(image.width()));
778  savedConfig.put("height",Value(image.height()));
779  }
780  if (!isOk()) { return false; }
781 
782  /* compute current audio and video time */
783  if (audio_st)
784  audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
785  else
786  audio_pts = 0.0;
787 
788  if (video_st)
789  video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
790  else
791  video_pts = 0.0;
792 
793  if (!(audio_st||video_st))
794  return false;
795 
796  /* write interleaved audio and video frames */
797  if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
798  write_audio_frame(oc, audio_st);
799  } else {
800  write_video_frame(oc, video_st, image);
801  }
802 
803  return true;
804 }
805 
806 
807 
808 bool FfmpegWriter::putAudioVisual(yarp::sig::ImageOf<yarp::sig::PixelRgb>& image,
809  yarp::sig::Sound& sound) {
810  if (delayed) {
811  savedConfig.put("width",Value(image.width()));
812  savedConfig.put("height",Value(image.height()));
813  savedConfig.put("sample_rate",Value(sound.getFrequency()));
814  savedConfig.put("channels",Value(sound.getChannels()));
815  savedConfig.put("audio",Value(1));
816  }
817  if (!isOk()) { return false; }
818 
819  /* write interleaved audio and video frames */
820  write_video_frame(oc, video_st, image);
821  write_audio_frame(oc, audio_st, sound);
822  return true;
823 }
T & safePixel(int x, int y)
Definition: Image.h:583
int getFrequency() const
Definition: Sound.cpp:183
float tincr2
#define url_fclose
Definition: ffmpeg_api.h:94
int audio_outbuf_size
#define CODEC_ID_MPEG2VIDEO
Definition: ffmpeg_api.h:92
delete image
Definition: IplImage.cpp:897
#define url_fopen
Definition: ffmpeg_api.h:93
#define av_alloc_format_context
Definition: ffmpeg_api.h:68
#define CODEC_ID_PCM_S16LE
Definition: ffmpeg_api.h:87
A base class for nested structures that can be searched.
Definition: Searchable.h:56
unsigned char g
Definition: Image.h:423
virtual ConstString toString() const =0
Return a standard text representation of the content of the object.
#define CODEC_TYPE_AUDIO
Definition: ffmpeg_api.h:61
int width() const
Gets width of image in pixels.
Definition: Image.h:101
if(image->origin==IPL_ORIGIN_TL) image -> imageDataOrigin=image->imageData+image->imageSize - image->widthStep
#define CODEC_ID_PCM_U16BE
Definition: ffmpeg_api.h:90
static void make_audio_frame(AVCodecContext *c, AVFrame *&frame, void *&samples)
static void write_audio_frame(AVFormatContext *oc, AVStream *st)
static AVStream * add_audio_stream(AVFormatContext *oc, CodecID codec_id)
Class for storing sounds.
Definition: Sound.h:25
static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
#define CODEC_ID_PCM_S16BE
Definition: ffmpeg_api.h:88
void exit(int exit_code)
Portable wrapper for the exit() function.
Definition: Os.cpp:40
#define CODEC_TYPE_VIDEO
Definition: ffmpeg_api.h:60
int samples_size
float t
An interface for the device drivers.
#define YARP_avcodec_alloc_frame
Definition: ffmpeg_api.h:75
int getSamples() const
Definition: Sound.h:98
#define DBG
int samples_channels
uint8_t * audio_outbuf
static AVFrame * alloc_picture(int pix_fmt, int width, int height)
int audio_input_frame_size
#define YARP_dump_format
Definition: ffmpeg_api.h:82
static void open_audio(AVFormatContext *oc, AVStream *st)
#define CODEC_ID_NONE
Definition: ffmpeg_api.h:86
#define CODEC_ID_PCM_U16LE
Definition: ffmpeg_api.h:89
#define av_new_stream(x, v)
Definition: ffmpeg_api.h:98
#define URL_WRONLY
Definition: ffmpeg_api.h:95
#define CODEC_ID_MPEG1VIDEO
Definition: ffmpeg_api.h:91
virtual bool isOk() override
Definition: TcpRosStream.h:87
int samples_at
float tincr
int stable_img_convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src, int src_pix_fmt, int src_width, int src_height)
Definition: ffmpeg_api.cpp:11
int getChannels() const
Definition: Sound.h:100
A single value (typically within a Bottle).
Definition: Value.h:36
virtual bool check(const ConstString &key) const =0
Check if there exists a property of the given name.
dest h
Definition: ImageCopy.cpp:63
return ret
Definition: IplImage.cpp:876
#define STREAM_PIX_FMT
static void fill_rgb_image(AVFrame *pict, int frame_index, int width, int height, ImageOf< PixelRgb > &img)
An interface to the operating system, including Port based communication.
dest v
Definition: ImageCopy.cpp:62
int16_t * samples
static void close_audio(AVFormatContext *oc, AVStream *st)
#define CodecID
Definition: ffmpeg_api.h:85
static AVStream * add_video_stream(AVFormatContext *oc, CodecID codec_id, int w, int h, int framerate)
unsigned char b
Definition: Image.h:423
Signal processing.
Definition: Image.h:20
#define guess_format
Definition: ffmpeg_api.h:67
int height() const
Gets height of image in pixels.
Definition: Image.h:107
unsigned char r
Definition: Image.h:423
#define PKT_FLAG_KEY
Definition: ffmpeg_api.h:66
int get(int sample, int channel=0) const
Definition: Sound.cpp:156
#define av_write_header(x)
Definition: ffmpeg_api.h:97
#define M_PI
Image file operations.
Definition: ImageFile.h:21