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