51#define M_PI 3.1415926535897931
54#define STREAM_FRAME_RATE 25
55#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P
56#define STREAM_PIX_WORK AV_PIX_FMT_RGB24
90 st = avformat_new_stream(oc, NULL);
92 yCFatal(FFMPEGWRITER,
"Could not alloc stream");
96 c->codec_id = codec_id;
97 c->codec_type = AVMEDIA_TYPE_AUDIO;
101 c->sample_rate = 44100;
108 yCInfo(FFMPEGWRITER,
"Opening audio stream");
115 codec = avcodec_find_encoder(c->codec_id);
117 yCFatal(FFMPEGWRITER,
"Audio codec not found");
121 if (avcodec_open2(c, codec,
nullptr) < 0) {
122 yCFatal(FFMPEGWRITER,
"Could not open codec");
127 tincr = 2 *
M_PI * 110.0 / c->sample_rate;
129 tincr2 = 2 *
M_PI * 110.0 / c->sample_rate / c->sample_rate;
136 if (c->frame_size <= 1) {
138 switch(st->codec->codec_id) {
139 case AV_CODEC_ID_PCM_S16LE:
140 case AV_CODEC_ID_PCM_S16BE:
141 case AV_CODEC_ID_PCM_U16LE:
142 case AV_CODEC_ID_PCM_U16BE:
158 "FRAME SIZE is %d / samples size is %d\n",
171 for(j=0;j<frame_size;j++) {
172 v = (int)(sin(
t) * 10000);
173 for (i = 0; i < nb_channels; i++) {
183 frame = av_frame_alloc();
185 yCFatal(FFMPEGWRITER,
"Could not allocate audio frame");
187 frame->nb_samples = c->frame_size;
188 frame->format = c->sample_fmt;
189 frame->channel_layout = c->channel_layout;
190 int buffer_size = av_samples_get_buffer_size(
nullptr, c->channels,
193 if (buffer_size < 0) {
194 yCError(FFMPEGWRITER,
"Could not get sample buffer size");
196 samples = av_malloc(buffer_size);
199 "Could not allocate %d bytes for samples buffer",
203 int ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
204 (
const uint8_t*)
samples, buffer_size, 0);
206 yCFatal(FFMPEGWRITER,
"Could not setup audio frame");
214 av_init_packet(&pkt);
225 av_init_packet(&tmp);
228 pkt.size = avcodec_encode_audio2(c, &tmp, frame, &got_packet);
229 if (tmp.side_data_elems > 0) {
230 for (
int i = 0; i < tmp.side_data_elems; i++) {
231 av_free(tmp.side_data[i].data);
233 av_freep(&tmp.side_data);
234 tmp.side_data_elems = 0;
237 av_frame_free(&frame);
239 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
240 pkt.flags |= AV_PKT_FLAG_KEY;
241 pkt.stream_index= st->index;
245 if (av_write_frame(oc, &pkt) != 0) {
246 yCFatal(FFMPEGWRITER,
"Error while writing audio frame");
248 yCInfo(FFMPEGWRITER,
"Wrote some audio");
254 yCInfo(FFMPEGWRITER,
"Preparing to write audio (%d left over)",
samples_at);
266 if (remain<avail) { avail = remain; }
267 for (
int i=0; i<avail; i++) {
279 av_init_packet(&pkt);
287 av_init_packet(&tmp);
290 pkt.size = avcodec_encode_audio2(c, &tmp, frame, &got_packet);
291 if (tmp.side_data_elems > 0) {
292 for (
int i = 0; i < tmp.side_data_elems; i++) {
293 av_free(tmp.side_data[i].data);
295 av_freep(&tmp.side_data);
296 tmp.side_data_elems = 0;
299 av_frame_free(&frame);
301 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base,
304 yCTrace(FFMPEGWRITER,
"(%d)", pkt.size);
306 pkt.flags |= AV_PKT_FLAG_KEY;
309 pkt.stream_index= st->index;
315 if (av_write_frame(oc, &pkt) != 0) {
316 yCFatal(FFMPEGWRITER,
"Error while writing audio frame");
321 yCInfo(FFMPEGWRITER,
" wrote audio\n");
326 avcodec_close(st->codec);
343 st = avformat_new_stream(oc, NULL);
345 yCFatal(FFMPEGWRITER,
"Could not alloc stream");
349 c->codec_id = codec_id;
350 c->codec_type = AVMEDIA_TYPE_VIDEO;
353 c->bit_rate = 400000;
362 c->time_base.num = 1;
365 if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
369 if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO){
376 if (!strcmp(oc->oformat->name,
"mp4") || !strcmp(oc->oformat->name,
"mov") || !strcmp(oc->oformat->name,
"3gp")) {
377 c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
387 uint8_t *picture_buf;
390 picture = av_frame_alloc();
394 size = avpicture_get_size((AVPixelFormat)pix_fmt, width, height);
395 picture_buf = (uint8_t*)av_malloc(size);
400 avpicture_fill((AVPicture *)picture, picture_buf,
401 (AVPixelFormat)pix_fmt, width, height);
405void FfmpegWriter::open_video(AVFormatContext *oc, AVStream *st)
407 yCInfo(FFMPEGWRITER,
"Opening video stream");
414 codec = avcodec_find_encoder(c->codec_id);
416 yCFatal(FFMPEGWRITER,
"Video codec not found");
420 if (avcodec_open2(c, codec,
nullptr) < 0) {
421 yCFatal(FFMPEGWRITER,
"Could not open codec");
424 video_outbuf =
nullptr;
431 video_outbuf_size = 200000;
432 video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
437 yCFatal(FFMPEGWRITER,
"Could not allocate picture");
443 tmp_picture =
nullptr;
444 if (c->pix_fmt != AV_PIX_FMT_RGB24) {
445 tmp_picture =
alloc_picture(AV_PIX_FMT_RGB24, c->width, c->height);
447 yCFatal(FFMPEGWRITER,
"Could not allocate temporary picture");
457 for(y=0;y<height;y++) {
458 for(x=0;x<width;x++) {
459 int base = y*(width*3);
460 pict->data[0][base + x*3] = img.
safePixel(x,y).
r;
461 pict->data[0][base +x*3+1] = img.
safePixel(x,y).
g;
462 pict->data[0][base +x*3+2] = img.
safePixel(x,y).
b;
468void FfmpegWriter::write_video_frame(AVFormatContext *oc, AVStream *st,
476 if (c->pix_fmt != AV_PIX_FMT_RGB24) {
477 fill_rgb_image(tmp_picture, frame_count, c->width, c->height, img);
479 (AVPicture *)tmp_picture, AV_PIX_FMT_RGB24,
480 c->width, c->height);
488 av_init_packet(&tmp);
489 tmp.data = video_outbuf;
490 tmp.size = video_outbuf_size;
491 out_size = avcodec_encode_video2(c, &tmp, picture, &got_packet);
492 if (tmp.side_data_elems > 0) {
493 for (
int i = 0; i < tmp.side_data_elems; i++) {
494 av_free(tmp.side_data[i].data);
496 av_freep(&tmp.side_data);
497 tmp.side_data_elems = 0;
502 av_init_packet(&pkt);
504 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
505 if (c->coded_frame->key_frame) {
506 pkt.flags |= AV_PKT_FLAG_KEY;
508 pkt.stream_index= st->index;
509 pkt.data= video_outbuf;
526 ret = av_write_frame(oc, &pkt);
532 yCFatal(FFMPEGWRITER,
"Error while writing video frame");
537void FfmpegWriter::close_video(AVFormatContext *oc, AVStream *st)
539 avcodec_close(st->codec);
540 av_free(picture->data[0]);
543 av_free(tmp_picture->data[0]);
544 av_free(tmp_picture);
546 av_free(video_outbuf);
557 "ffmpeg libavcodec version number %d.%d.%d",
558 LIBAVCODEC_VERSION_MAJOR,
559 LIBAVCODEC_VERSION_MINOR,
560 LIBAVCODEC_VERSION_MICRO);
566 return delayedOpen(config);
574 "width of image (must be even)").asInt32();
576 "height of image (must be even)").asInt32();
578 "baseline images per second").asInt32();
582 bool audio = config.
check(
"audio",
"should audio be included");
584 sample_rate = config.
check(
"sample_rate",
Value(44100),
585 "audio samples per second").asInt32();
587 "audio samples per second").asInt32();
590 filename = config.
check(
"out",
Value(
"movie.avi"),
591 "name of movie to write").asString();
605 fmt = av_guess_format(
nullptr, filename.c_str(),
nullptr);
607 yCInfo(FFMPEGWRITER,
"Could not deduce output format from file extension: using MPEG.");
608 fmt = av_guess_format(
"mpeg",
nullptr,
nullptr);
611 yCFatal(FFMPEGWRITER,
"Could not find suitable output format");
615 oc = avformat_alloc_context();
617 yCFatal(FFMPEGWRITER,
"Memory error");
620 snprintf(oc->filename,
sizeof(oc->filename),
"%s", filename.c_str());
626 if (fmt->video_codec != AV_CODEC_ID_NONE) {
631 yCInfo(FFMPEGWRITER,
"Adding audio %dx%d", sample_rate, channels);
632 if (fmt->audio_codec != AV_CODEC_ID_NONE) {
634 if (audio_st!=
nullptr) {
635 AVCodecContext *c = audio_st->codec;
636 c->sample_rate = sample_rate;
637 c->channels = channels;
639 yCError(FFMPEGWRITER,
"Failed to add audio");
642 yCWarning(FFMPEGWRITER,
"No audio codec available");
645 yCInfo(FFMPEGWRITER,
"Skipping audio");
648 av_dump_format(oc, 0, filename.c_str(), 1);
653 open_video(oc, video_st);
660 if (!(fmt->flags & AVFMT_NOFILE)) {
661 if (avio_open(&oc->pb, filename.c_str(), AVIO_FLAG_WRITE) < 0) {
662 yCFatal(FFMPEGWRITER,
"Could not open '%s'", filename.c_str());
667 avformat_write_header(oc, NULL);
673 if (!isOk()) {
return false; }
677 close_video(oc, video_st);
684 av_write_trailer(oc);
687 for(
unsigned int i = 0; i < oc->nb_streams; i++) {
688 av_freep(&oc->streams[i]->codec);
689 av_freep(&oc->streams[i]);
692 if (!(fmt->flags & AVFMT_NOFILE)) {
700 yCInfo(FFMPEGWRITER,
"Closed media file %s", filename.c_str());
710 if (!isOk()) {
return false; }
714 audio_pts = (double)av_stream_get_end_pts(audio_st) * audio_st->time_base.num / audio_st->time_base.den;
720 video_pts = (double)av_stream_get_end_pts(video_st) * video_st->time_base.num / video_st->time_base.den;
725 if (!(audio_st || video_st)) {
730 if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
733 write_video_frame(oc, video_st, image);
750 if (!isOk()) {
return false; }
753 write_video_frame(oc, video_st, image);
static AVStream * add_video_stream(AVFormatContext *oc, AVCodecID codec_id, int w, int h, int framerate)
static AVFrame * alloc_picture(int pix_fmt, int width, int height)
static AVStream * add_audio_stream(AVFormatContext *oc, AVCodecID codec_id)
static void write_audio_frame(AVFormatContext *oc, AVStream *st)
static void close_audio(AVFormatContext *oc, AVStream *st)
static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
static void make_audio_frame(AVCodecContext *c, AVFrame *&frame, void *&samples)
int audio_input_frame_size
static void fill_rgb_image(AVFrame *pict, int frame_index, int width, int height, ImageOf< PixelRgb > &img)
static void open_audio(AVFormatContext *oc, AVStream *st)
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
bool putImage(yarp::sig::ImageOf< yarp::sig::PixelRgb > &image) override
Write an image to the device.
bool close() override
Close the DeviceDriver.
virtual bool putAudioVisual(yarp::sig::ImageOf< yarp::sig::PixelRgb > &image, yarp::sig::Sound &sound) override
Write an image and sound.
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
A base class for nested structures that can be searched.
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.
A single value (typically within a Bottle).
T & safePixel(size_t x, size_t y)
size_t width() const
Gets width of image in pixels.
size_t height() const
Gets height of image in pixels.
Class for storing sounds See Audio in YARP for additional documentation on YARP audio.
size_t getChannels() const
Get the number of channels of the sound.
int getFrequency() const
Get the frequency of the sound (i.e.
audio_sample get(size_t sample, size_t channel=0) const
size_t getSamples() const
Get the number of samples contained in the sound.
int stable_img_convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src, int src_pix_fmt, int src_width, int src_height)
#define yCInfo(component,...)
#define yCError(component,...)
#define yCTrace(component,...)
#define yCWarning(component,...)
#define YARP_LOG_COMPONENT(name,...)
#define yCFatal(component,...)
For streams capable of holding different kinds of content, check what they actually have.
An interface to the operating system, including Port based communication.
constexpr char framerate[]