ff-save.c 26.1 KB
Newer Older
1 2 3 4 5
/* This file is an image processing operation for GEGL
 *
 * GEGL is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
6
 * version 3 of the License, or (at your option) any later version.
7 8 9 10 11 12 13
 *
 * GEGL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
14
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
15
 *
16
 * Copyright 2003,2004,2007, 2015 Øyvind Kolås <pippin@gimp.org>
17
 */
18 19

#include "config.h"
Martin Nordholts's avatar
Martin Nordholts committed
20 21 22

#include <stdlib.h>

23 24
#include <glib/gi18n-lib.h>

25
#ifdef GEGL_PROPERTIES
26

27
property_string (path, _("File"), "/tmp/fnord.ogv")
28
    description (_("Target path and filename, use '-' for stdout."))
29

30 31 32 33 34
property_audio_fragment (audio, _("audio"), 0)
property_string (audio_codec, _("Audio codec"), "auto")
property_int (audio_bit_rate, _("audio bitrate in kb/s"), 64)
    description (_("Target encoded video bitrate in kb/s"))

35 36
property_double (frame_rate, _("Frames/second"), 25.0)
    value_range (0.0, 100.0)
37

38
property_string (video_codec, _("Video codec"), "auto")
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
property_int (video_bit_rate, _("video bitrate in kb/s"), 128)
    description (_("Target encoded video bitrate in kb/s"))

property_int (global_quality, _("global quality"), 0)
property_int (noise_reduction, _("noise reduction"), 0)
property_int (scenechange_threshold, _("scenechange threshold"), 0)
property_int (video_bit_rate_min, _("video bitrate min"), 0)
property_int (video_bit_rate_max, _("video bitrate max"), 0)
property_int (video_bit_rate_tolerance, _("video bitrate tolerance"), 0)

property_int (keyint_min, _("keyint-min"), 0)
property_int (trellis, _("trellis"), 0)
property_int (qmin, _("qmin"), 0)
property_int (qmax, _("qmax"), 0)
property_int (max_qdiff, _("max_qdiff"), 0)
property_int (me_range, _("me_range"), 0)
property_int (max_b_frames, _("max_b_frames"), 0)
property_int (gop_size, _("gop-size"), 0)
property_double (qcompress, _("qcompress"), 0.0)
property_double (qblur, _("qblur"), 0.0)
property_double (i_quant_factor, _("i-quant-factor"), 0.0)
property_double (i_quant_offset, _("i-quant-offset"), 0.0)
property_int (me_subpel_quality, _("me-subpel-quality"), 0)
62

63

64

65 66
#else

67
#define GEGL_OP_SINK
68
#define GEGL_OP_C_SOURCE ff-save.c
69

70
#include "gegl-op.h"
71

72
#include <libavformat/avformat.h>
73 74 75 76
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

typedef struct
{
  gdouble    frame;
  gdouble    frames;
  gdouble    width;
  gdouble    height;
  GeglBuffer *input;

  AVOutputFormat *fmt;
  AVFormatContext *oc;
  AVStream *video_st;

  AVFrame  *picture, *tmp_picture;
  uint8_t  *video_outbuf;
  int       frame_count, video_outbuf_size;
93
  int       audio_sample_rate;
94

95 96 97 98
    /** the rest is for audio handling within oxide, note that the interface
     * used passes all used functions in the oxide api through the reg_sym api
     * of gggl, this means that the ops should be usable by other applications
     * using gggl directly,. without needing to link with the oxide library
99 100 101 102 103 104 105 106 107 108 109 110
     */
  AVStream *audio_st;

  uint32_t  sample_rate;
  uint32_t  bits;
  uint32_t  channels;
  uint32_t  fragment_samples;
  uint32_t  fragment_size;

  int       buffer_size;
  int       buffer_read_pos;
  int       buffer_write_pos;
111 112
  uint8_t  *buffer; 
                   
113 114
  int       audio_outbuf_size;
  int16_t  *samples;
115

116 117 118
  GList    *audio_track;
  long      audio_pos;
  long      audio_read_pos;
119 120
  
  int       next_apts;
121 122
} Priv;

123 124 125 126 127 128
static void
clear_audio_track (GeglProperties *o)
{
  Priv *p = (Priv*)o->user_data;
  while (p->audio_track)
    {
129
      g_object_unref (p->audio_track->data);
130 131 132 133 134 135 136 137 138 139
      p->audio_track = g_list_remove (p->audio_track, p->audio_track->data);
    }
}

static void get_sample_data (Priv *p, long sample_no, float *left, float *right)
{
  int to_remove = 0;
  GList *l;
  if (sample_no < 0)
    return;
140
  for (l = p->audio_track; l; l = l->next)
141
  {
142
    GeglAudioFragment *af = l->data;
143 144 145
    int channels = gegl_audio_fragment_get_channels (af);
    int pos = gegl_audio_fragment_get_pos (af);
    int sample_count = gegl_audio_fragment_get_sample_count (af);
146
    if (sample_no > pos + sample_count)
147 148 149 150
    {
      to_remove ++;
    }

151 152
    if (pos <= sample_no &&
        sample_no < pos + sample_count)
153
      {
154
        int i = sample_no - pos;
155
        *left  = af->data[0][i];
156
        if (channels == 1)
157 158 159 160 161 162 163 164 165
          *right = af->data[0][i];
        else
          *right = af->data[1][i];

	if (to_remove)  /* consuming audiotrack */
        {
          again:
          for (l = p->audio_track; l; l = l->next)
          {
166
            GeglAudioFragment *af = l->data;
167 168
            int pos = gegl_audio_fragment_get_pos (af);
            int sample_count = gegl_audio_fragment_get_sample_count (af);
169
            if (sample_no > pos + sample_count)
170 171
            {
              p->audio_track = g_list_remove (p->audio_track, af);
172
              g_object_unref (af);
173 174 175 176 177 178 179 180 181 182
              goto again;
            }
          }
        }
        return;
      }
  }
  *left  = 0;
  *right = 0;
}
183

Kevin Cozens's avatar
Kevin Cozens committed
184
static void
185
init (GeglProperties *o)
186
{
Kevin Cozens's avatar
Kevin Cozens committed
187
  static gint inited = 0; /*< this is actually meant to be static, only to be done once */
188
  Priv       *p = (Priv*)o->user_data;
Kevin Cozens's avatar
Kevin Cozens committed
189 190

  if (p == NULL)
191
    {
Kevin Cozens's avatar
Kevin Cozens committed
192
      p = g_new0 (Priv, 1);
193
      o->user_data = (void*) p;
194 195 196 197 198 199 200 201 202
    }

  if (!inited)
    {
      av_register_all ();
      avcodec_register_all ();
      inited = 1;
    }

203 204 205
  clear_audio_track (o);
  p->audio_pos = 0;
  p->audio_read_pos = 0;
206 207

  p->audio_sample_rate = -1; /* only do this if it hasn't been manually set? */
208 209
}

Kevin Cozens's avatar
Kevin Cozens committed
210 211 212 213 214 215
static void close_video       (Priv            *p,
                               AVFormatContext *oc,
                               AVStream        *st);
void        close_audio       (Priv            *p,
                               AVFormatContext *oc,
                               AVStream        *st);
216 217
static int  tfile             (GeglProperties  *o);
static void write_video_frame (GeglProperties  *o,
Kevin Cozens's avatar
Kevin Cozens committed
218 219
                               AVFormatContext *oc,
                               AVStream        *st);
220
static void write_audio_frame (GeglProperties      *o,
Kevin Cozens's avatar
Kevin Cozens committed
221 222
                               AVFormatContext *oc,
                               AVStream        *st);
223 224 225

#define STREAM_FRAME_RATE 25    /* 25 images/s */

226
#ifndef DISABLE_AUDIO
227 228
/* add an audio output stream */
static AVStream *
229
add_audio_stream (GeglProperties *o, AVFormatContext * oc, int codec_id)
230 231 232 233
{
  AVCodecContext *c;
  AVStream *st;

234
  st = avformat_new_stream (oc, NULL);
235 236 237 238 239 240 241 242
  if (!st)
    {
      fprintf (stderr, "Could not alloc stream\n");
      exit (1);
    }

  c = st->codec;
  c->codec_id = codec_id;
243
  c->codec_type = AVMEDIA_TYPE_AUDIO;
244

245 246 247
  if (oc->oformat->flags & AVFMT_GLOBALHEADER)
    c->flags |= CODEC_FLAG_GLOBAL_HEADER;

248 249
  return st;
}
250
#endif
251 252

static void
253
open_audio (GeglProperties *o, AVFormatContext * oc, AVStream * st)
254
{
255
  Priv *p = (Priv*)o->user_data;
256 257
  AVCodecContext *c;
  AVCodec  *codec;
258
  int i;
259 260 261 262 263 264 265 266 267 268

  c = st->codec;

  /* find the audio encoder */
  codec = avcodec_find_encoder (c->codec_id);
  if (!codec)
    {
      fprintf (stderr, "codec not found\n");
      exit (1);
    }
269
  c->bit_rate = o->audio_bit_rate * 1000;
270 271
  c->sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;

272 273 274 275
  if (p->audio_sample_rate == -1)
  {
    if (o->audio)
    {
276
      if (gegl_audio_fragment_get_sample_rate (o->audio) == 0)
277
      {
278
        gegl_audio_fragment_set_sample_rate (o->audio, 48000); // XXX: should skip adding audiostream instead
279
      }
280
      p->audio_sample_rate = gegl_audio_fragment_get_sample_rate (o->audio);
281 282 283
    }
  }
  c->sample_rate = p->audio_sample_rate;
284 285 286
  c->channel_layout = AV_CH_LAYOUT_STEREO;
  c->channels = 2;

287

288 289 290 291
  if (codec->supported_samplerates)
  {
    c->sample_rate = codec->supported_samplerates[0];
    for (i = 0; codec->supported_samplerates[i]; i++)
292 293 294 295
    {
      if (codec->supported_samplerates[i] == p->audio_sample_rate)
         c->sample_rate = p->audio_sample_rate;
    }
296
  }
297 298
  //st->time_base = (AVRational){1, c->sample_rate};
  st->time_base = (AVRational){1, p->audio_sample_rate};
299 300

  c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; // ffmpeg AAC is not quite stable yet
301 302

  /* open it */
303
  if (avcodec_open2 (c, codec, NULL) < 0)
304 305 306 307 308 309
    {
      fprintf (stderr, "could not open codec\n");
      exit (1);
    }
}

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
                                  uint64_t channel_layout,
                                  int sample_rate, int nb_samples)
{
  AVFrame *frame = av_frame_alloc();
  int ret;

  if (!frame) {
      fprintf(stderr, "Error allocating an audio frame\n");
      exit(1);
  }

  frame->format         = sample_fmt;
  frame->channel_layout = channel_layout;
  frame->sample_rate    = sample_rate;
  frame->nb_samples     = nb_samples;

  if (nb_samples) {
      ret = av_frame_get_buffer(frame, 0);
      if (ret < 0) {
          fprintf(stderr, "Error allocating an audio buffer\n");
          exit(1);
      }
  }
  return frame;
}

337
void
338
write_audio_frame (GeglProperties *o, AVFormatContext * oc, AVStream * st)
339
{
340
  Priv *p = (Priv*)o->user_data;
341 342 343 344 345 346 347 348
  AVCodecContext *c = st->codec;
  int sample_count = 100000;
  static AVPacket  pkt = { 0 };

  if (pkt.size == 0)
  {
    av_init_packet (&pkt);
  }
349

350 351 352
  /* first we add incoming frames audio samples */
  {
    int i;
353 354 355 356 357
    int sample_count = gegl_audio_fragment_get_sample_count (o->audio);
    GeglAudioFragment *af = gegl_audio_fragment_new (gegl_audio_fragment_get_sample_rate (o->audio),
                                                     gegl_audio_fragment_get_channels (o->audio),
                                                     gegl_audio_fragment_get_channel_layout (o->audio),
                                                     sample_count);
358
    gegl_audio_fragment_set_sample_count (af, sample_count);
359
    for (i = 0; i < sample_count; i++)
360
      {
361 362
        af->data[0][i] = o->audio->data[0][i];
        af->data[1][i] = o->audio->data[1][i];
363
      }
364 365
    gegl_audio_fragment_set_pos (af, p->audio_pos);
    p->audio_pos += sample_count;
366 367 368
    p->audio_track = g_list_append (p->audio_track, af);
  }

369 370 371
  if (!(c->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
    sample_count = c->frame_size;

372
  /* then we encode as much as we can in a loop using the codec frame size */
373

374
  
375
  while (p->audio_pos - p->audio_read_pos > sample_count)
376 377
  {
    long i;
378 379
    int ret;
    int got_packet = 0;
380
    AVFrame *frame = alloc_audio_frame (c->sample_fmt, c->channel_layout,
381
                                        c->sample_rate, sample_count);
382

383 384
    switch (c->sample_fmt) {
      case AV_SAMPLE_FMT_FLT:
385
        for (i = 0; i < sample_count; i++)
386 387 388 389 390 391 392 393
        {
          float left = 0, right = 0;
          get_sample_data (p, i + p->audio_read_pos, &left, &right);
          ((float*)frame->data[0])[c->channels*i+0] = left;
          ((float*)frame->data[0])[c->channels*i+1] = right;
        }
        break;
      case AV_SAMPLE_FMT_FLTP:
394
        for (i = 0; i < sample_count; i++)
395 396 397 398 399 400 401
        {
          float left = 0, right = 0;
          get_sample_data (p, i + p->audio_read_pos, &left, &right);
          ((float*)frame->data[0])[i] = left;
          ((float*)frame->data[1])[i] = right;
        }
        break;
402
      case AV_SAMPLE_FMT_S16:
403
        for (i = 0; i < sample_count; i++)
404 405 406 407 408 409 410
        {
          float left = 0, right = 0;
          get_sample_data (p, i + p->audio_read_pos, &left, &right);
          ((int16_t*)frame->data[0])[c->channels*i+0] = left * (1<<15);
          ((int16_t*)frame->data[0])[c->channels*i+1] = right * (1<<15);
        }
        break;
411
      case AV_SAMPLE_FMT_S32:
412
        for (i = 0; i < sample_count; i++)
413 414 415 416 417 418 419 420
        {
          float left = 0, right = 0;
          get_sample_data (p, i + p->audio_read_pos, &left, &right);
          ((int32_t*)frame->data[0])[c->channels*i+0] = left * (1<<31);
          ((int32_t*)frame->data[0])[c->channels*i+1] = right * (1<<31);
        }
        break;
      case AV_SAMPLE_FMT_S32P:
421
        for (i = 0; i < sample_count; i++)
422 423 424 425 426 427
        {
          float left = 0, right = 0;
          get_sample_data (p, i + p->audio_read_pos, &left, &right);
          ((int32_t*)frame->data[0])[i] = left * (1<<31);
          ((int32_t*)frame->data[1])[i] = right * (1<<31);
        }
428 429
        break;
      case AV_SAMPLE_FMT_S16P:
430
        for (i = 0; i < sample_count; i++)
431 432 433 434 435 436
        {
          float left = 0, right = 0;
          get_sample_data (p, i + p->audio_read_pos, &left, &right);
          ((int16_t*)frame->data[0])[i] = left * (1<<15);
          ((int16_t*)frame->data[1])[i] = right * (1<<15);
        }
437 438 439 440 441
        break;
      default:
        fprintf (stderr, "eeeek unhandled audio format\n");
        break;
    }
442
    frame->pts = p->next_apts;
443
    p->next_apts += sample_count;
444 445 446

    av_frame_make_writable (frame);
    ret = avcodec_encode_audio2 (c, &pkt, frame, &got_packet);
447 448

    av_packet_rescale_ts (&pkt, st->codec->time_base, st->time_base);
449 450 451 452 453
    if (ret < 0) {
      fprintf (stderr, "Error encoding audio frame: %s\n", av_err2str (ret));
    }

    if (got_packet)
454
    {
455 456
      pkt.stream_index = st->index;
      av_interleaved_write_frame (oc, &pkt);
457
      av_free_packet (&pkt);
458 459 460
    }

    av_frame_free (&frame);
461
    p->audio_read_pos += sample_count;
462
  }
463 464 465 466 467 468 469 470 471 472 473
}

void
close_audio (Priv * p, AVFormatContext * oc, AVStream * st)
{
  avcodec_close (st->codec);

}

/* add a video output stream */
static AVStream *
474
add_video_stream (GeglProperties *o, AVFormatContext * oc, int codec_id)
475
{
476
  Priv *p = (Priv*)o->user_data;
477 478 479 480

  AVCodecContext *c;
  AVStream *st;

481
  st = avformat_new_stream (oc, NULL);
482 483
  if (!st)
    {
484
      fprintf (stderr, "Could not alloc stream %p %p %i\n", o, oc, codec_id);
485 486 487 488 489
      exit (1);
    }

  c = st->codec;
  c->codec_id = codec_id;
490
  c->codec_type = AVMEDIA_TYPE_VIDEO;
491
  /* put sample propeters */
492 493 494 495 496
  fprintf (stderr, "{{ %i %i %i\n", c->bit_rate, c->rc_min_rate, c->rc_max_rate);
  c->bit_rate = o->video_bit_rate * 1000;
  c->rc_min_rate = o->video_bit_rate_min * 1000;
  c->rc_max_rate = o->video_bit_rate_max * 1000;
  c->bit_rate_tolerance = o->video_bit_rate_tolerance * 1000;
497 498 499 500
  /* resolution must be a multiple of two */
  c->width = p->width;
  c->height = p->height;
  /* frames per second */
501
  st->time_base =(AVRational){1, o->frame_rate};
502 503
  c->time_base = st->time_base;
  c->pix_fmt = AV_PIX_FMT_YUV420P;
504

505
  if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO)
506
    {
507
      c->max_b_frames = 2;
508
    }
509

510 511
  if (c->codec_id == AV_CODEC_ID_H264)
   {
512 513 514 515
     c->qcompress = 0.6;  // qcomp=0.6
     c->me_range = 16;    // me_range=16
     c->gop_size = 250;   // g=250
     c->max_b_frames = 3; // bf=3
516 517
   }

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
  if (o->global_quality)
     c->global_quality = o->global_quality;
  if (o->qcompress != 0.0)
     c->qcompress = o->qcompress;
  if (o->qblur != 0.0)
     c->qblur = o->qblur;
  if (o->max_qdiff != 0)
     c->max_qdiff = o->max_qdiff;
  if (o->me_subpel_quality != 0)
     c->me_subpel_quality = o->me_subpel_quality;
  if (o->i_quant_factor != 0.0)
     c->i_quant_factor = o->i_quant_factor;
  if (o->i_quant_offset != 0.0)
     c->i_quant_offset = o->i_quant_offset;
  if (o->max_b_frames)
    c->max_b_frames = o->max_b_frames;
  if (o->me_range)
    c->me_range = o->me_range;
  if (o->noise_reduction)
    c->noise_reduction = o->noise_reduction;
  if (o->scenechange_threshold)
    c->scenechange_threshold = o->scenechange_threshold;
  if (o->trellis)
    c->trellis = o->trellis;
  if (o->qmin)
    c->qmin = o->qmin;
  if (o->qmax)
    c->qmax = o->qmax;
  if (o->gop_size)
    c->gop_size = o->gop_size;
  if (o->keyint_min)
    c->keyint_min = o->keyint_min;

551 552 553
   if (oc->oformat->flags & AVFMT_GLOBALHEADER)
     c->flags |= CODEC_FLAG_GLOBAL_HEADER;

554 555 556 557 558 559 560 561 562 563 564
  return st;
}


static AVFrame *
alloc_picture (int pix_fmt, int width, int height)
{
  AVFrame  *picture;
  uint8_t  *picture_buf;
  int       size;

565
  picture = av_frame_alloc ();
566 567
  if (!picture)
    return NULL;
568
  size = avpicture_get_size (pix_fmt, width, height + 1);
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
  picture_buf = malloc (size);
  if (!picture_buf)
    {
      av_free (picture);
      return NULL;
    }
  avpicture_fill ((AVPicture *) picture, picture_buf, pix_fmt, width, height);
  return picture;
}

static void
open_video (Priv * p, AVFormatContext * oc, AVStream * st)
{
  AVCodec  *codec;
  AVCodecContext *c;

  c = st->codec;

  /* find the video encoder */
  codec = avcodec_find_encoder (c->codec_id);
  if (!codec)
    {
      fprintf (stderr, "codec not found\n");
      exit (1);
    }

  /* open the codec */
596
  if (avcodec_open2 (c, codec, NULL) < 0)
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
    {
      fprintf (stderr, "could not open codec\n");
      exit (1);
    }

  p->video_outbuf = NULL;
  if (!(oc->oformat->flags & AVFMT_RAWPICTURE))
    {
      /* allocate output buffer */
      /* XXX: API change will be done */
      p->video_outbuf_size = 200000;
      p->video_outbuf = malloc (p->video_outbuf_size);
    }

  /* allocate the encoded raw picture */
  p->picture = alloc_picture (c->pix_fmt, c->width, c->height);
  if (!p->picture)
    {
      fprintf (stderr, "Could not allocate picture\n");
      exit (1);
    }

  /* if the output format is not YUV420P, then a temporary YUV420P
     picture is needed too. It is then converted to the required
     output format */
  p->tmp_picture = NULL;
623
  if (c->pix_fmt != AV_PIX_FMT_RGB24)
624
    {
625
      p->tmp_picture = alloc_picture (AV_PIX_FMT_RGB24, c->width, c->height);
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
      if (!p->tmp_picture)
        {
          fprintf (stderr, "Could not allocate temporary picture\n");
          exit (1);
        }
    }
}

static void
close_video (Priv * p, AVFormatContext * oc, AVStream * st)
{
  avcodec_close (st->codec);
  av_free (p->picture->data[0]);
  av_free (p->picture);
  if (p->tmp_picture)
    {
      av_free (p->tmp_picture->data[0]);
      av_free (p->tmp_picture);
    }
  av_free (p->video_outbuf);
}

#include "string.h"

/* prepare a dummy image */
static void
652
fill_rgb_image (GeglProperties *o,
Kevin Cozens's avatar
Kevin Cozens committed
653
                AVFrame *pict, int frame_index, int width, int height)
654
{
655
  Priv     *p = (Priv*)o->user_data;
656
  GeglRectangle rect={0,0,width,height};
657
  gegl_buffer_get (p->input, &rect, 1.0, babl_format ("R'G'B' u8"), pict->data[0], GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
658 659 660
}

static void
661
write_video_frame (GeglProperties *o,
Kevin Cozens's avatar
Kevin Cozens committed
662
                   AVFormatContext *oc, AVStream *st)
663
{
664 665
  Priv           *p = (Priv*)o->user_data;
  int             out_size, ret;
666
  AVCodecContext *c;
667
  AVFrame        *picture_ptr;
668 669 670

  c = st->codec;

671
  if (c->pix_fmt != AV_PIX_FMT_RGB24)
672
    {
673
      struct SwsContext *img_convert_ctx;
674
      fill_rgb_image (o, p->tmp_picture, p->frame_count, c->width,
675
                      c->height);
676

677
      img_convert_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_RGB24,
678
                                       c->width, c->height, c->pix_fmt,
679 680 681 682 683 684 685 686 687
                                       SWS_BICUBIC, NULL, NULL, NULL);

      if (img_convert_ctx == NULL)
        {
          fprintf(stderr, "ff_save: Cannot initialize conversion context.");
        }
      else
        {
          sws_scale(img_convert_ctx,
688
                    (void*)p->tmp_picture->data,
689 690 691 692 693
                    p->tmp_picture->linesize,
                    0,
                    c->height,
                    p->picture->data,
                    p->picture->linesize);
694 695 696
         p->picture->format = c->pix_fmt;
         p->picture->width = c->width;
         p->picture->height = c->height;
697
        }
698 699 700
    }
  else
    {
701
      fill_rgb_image (o, p->picture, p->frame_count, c->width, c->height);
702
    }
703

704
  picture_ptr      = p->picture;
705
  picture_ptr->pts = p->frame_count;
706 707 708 709 710 711 712 713

  if (oc->oformat->flags & AVFMT_RAWPICTURE)
    {
      /* raw video case. The API will change slightly in the near
         future for that */
      AVPacket  pkt;
      av_init_packet (&pkt);

714
      pkt.flags |= AV_PKT_FLAG_KEY;
715 716 717
      pkt.stream_index = st->index;
      pkt.data = (uint8_t *) picture_ptr;
      pkt.size = sizeof (AVPicture);
718 719
      pkt.pts = picture_ptr->pts;
      av_packet_rescale_ts (&pkt, c->time_base, st->time_base);
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736

      ret = av_write_frame (oc, &pkt);
    }
  else
    {
      /* encode the image */
      out_size =
        avcodec_encode_video (c,
                              p->video_outbuf,
                              p->video_outbuf_size, picture_ptr);

      /* if zero size, it means the image was buffered */
      if (out_size != 0)
        {
          AVPacket  pkt;
          av_init_packet (&pkt);
          if (c->coded_frame->key_frame)
737
            pkt.flags |= AV_PKT_FLAG_KEY;
738 739 740
          pkt.stream_index = st->index;
          pkt.data = p->video_outbuf;
          pkt.size = out_size;
741 742
          pkt.pts = picture_ptr->pts;
          av_packet_rescale_ts (&pkt, c->time_base, st->time_base);
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
          /* write the compressed frame in the media file */
          ret = av_write_frame (oc, &pkt);
        }
      else
        {
          ret = 0;
        }
    }
  if (ret != 0)
    {
      fprintf (stderr, "Error while writing video frame\n");
      exit (1);
    }
  p->frame_count++;
}

static int
760
tfile (GeglProperties *o)
761
{
762
  Priv *p = (Priv*)o->user_data;
763

764
  p->fmt = av_guess_format (NULL, o->path, NULL);
765 766 767 768 769
  if (!p->fmt)
    {
      fprintf (stderr,
               "ff_save couldn't deduce outputformat from file extension: using MPEG.\n%s",
               "");
770
      p->fmt = av_guess_format ("mpeg", NULL, NULL);
771
    }
772
  p->oc = avformat_alloc_context ();
773 774 775 776 777 778 779 780
  if (!p->oc)
    {
      fprintf (stderr, "memory error\n%s", "");
      return -1;
    }

  p->oc->oformat = p->fmt;

781
  snprintf (p->oc->filename, sizeof (p->oc->filename), "%s", o->path);
782 783 784

  p->video_st = NULL;
  p->audio_st = NULL;
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
  
  if (strcmp (o->video_codec, "auto"))
  {
    AVCodec *codec = avcodec_find_encoder_by_name (o->video_codec);
    p->fmt->video_codec = AV_CODEC_ID_NONE;
    if (codec)
      p->fmt->video_codec = codec->id;
    else
      {
        fprintf (stderr, "didn't find video encoder \"%s\"\navailable codecs: ", o->video_codec);
        while ((codec = av_codec_next (codec)))
          if (av_codec_is_encoder (codec) &&
              avcodec_get_type (codec->id) == AVMEDIA_TYPE_VIDEO)
          fprintf (stderr, "%s ", codec->name);
        fprintf (stderr, "\n");
      }
  }
  if (strcmp (o->audio_codec, "auto"))
  {
    AVCodec *codec = avcodec_find_encoder_by_name (o->audio_codec);
    p->fmt->audio_codec = AV_CODEC_ID_NONE;
    if (codec)
      p->fmt->audio_codec = codec->id;
    else
      {
        fprintf (stderr, "didn't find audio encoder \"%s\"\navailable codecs: ", o->audio_codec);
        while ((codec = av_codec_next (codec)))
          if (av_codec_is_encoder (codec) &&
              avcodec_get_type (codec->id) == AVMEDIA_TYPE_AUDIO)
                fprintf (stderr, "%s ", codec->name);
        fprintf (stderr, "\n");
      }
  }
818

819
  if (p->fmt->video_codec != AV_CODEC_ID_NONE)
820
    {
821
      p->video_st = add_video_stream (o, p->oc, p->fmt->video_codec);
822
    }
823
  if (p->fmt->audio_codec != AV_CODEC_ID_NONE)
824
    {
825
     p->audio_st = add_audio_stream (o, p->oc, p->fmt->audio_codec);
826 827 828 829 830
    }


  if (p->video_st)
    open_video (p, p->oc, p->video_st);
831

832
  if (p->audio_st)
833
    open_audio (o, p->oc, p->audio_st);
834

835 836
  av_dump_format (p->oc, 0, o->path, 1);

837
  if (avio_open (&p->oc->pb, o->path, AVIO_FLAG_WRITE) < 0)
838
    {
839
      fprintf (stderr, "couldn't open '%s'\n", o->path);
840 841 842
      return -1;
    }

843
  avformat_write_header (p->oc, NULL);
844 845 846
  return 0;
}

Kevin Cozens's avatar
Kevin Cozens committed
847 848 849
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
850 851
         const GeglRectangle *result,
         gint                 level)
Kevin Cozens's avatar
Kevin Cozens committed
852
{
853
  GeglProperties *o = GEGL_PROPERTIES (operation);
854 855
  Priv           *p = (Priv*)o->user_data;
  static gint     inited = 0;
Kevin Cozens's avatar
Kevin Cozens committed
856 857 858 859 860

  g_assert (input);

  if (p == NULL)
    init (o);
861
  p = (Priv*)o->user_data;
Kevin Cozens's avatar
Kevin Cozens committed
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879

  p->width = result->width;
  p->height = result->height;
  p->input = input;

  if (!inited)
    {
      tfile (o);
      inited = 1;
    }

  write_video_frame (o, p->oc, p->video_st);
  if (p->audio_st)
    write_audio_frame (o, p->oc, p->audio_st);

  return  TRUE;
}

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
static void flush_audio (GeglProperties *o)
{
  Priv *p = (Priv*)o->user_data;

  int got_packet;
  do
  {
    AVPacket  pkt = { 0 };
    int ret;
    got_packet = 0;
    av_init_packet (&pkt);
    ret = avcodec_encode_audio2 (p->audio_st->codec, &pkt, NULL, &got_packet);
    if (ret < 0)
      break;
    if (got_packet)
      {
        pkt.stream_index = p->audio_st->index;
        av_packet_rescale_ts (&pkt, p->audio_st->codec->time_base, p->audio_st->time_base);
        av_interleaved_write_frame (p->oc, &pkt);
        av_free_packet (&pkt);
      }
  } while (got_packet);
}

static void flush_video (GeglProperties *o)
{
  Priv *p = (Priv*)o->user_data;
  int got_packet = 0;
  do {
    AVPacket  pkt = { 0 };
    int ret;
    got_packet = 0;
    av_init_packet (&pkt);
    ret = avcodec_encode_video2 (p->video_st->codec, &pkt, NULL, &got_packet);
    if (ret < 0)
      return;
      
     if (got_packet)
     {
       pkt.stream_index = p->video_st->index;
       av_packet_rescale_ts (&pkt, p->video_st->codec->time_base, p->video_st->time_base);
       av_interleaved_write_frame (p->oc, &pkt);
       av_free_packet (&pkt);
     }
  } while (got_packet);
}

Kevin Cozens's avatar
Kevin Cozens committed
927 928 929
static void
finalize (GObject *object)
{
930 931
  GeglProperties *o = GEGL_PROPERTIES (object);
  if (o->user_data)
Kevin Cozens's avatar
Kevin Cozens committed
932
    {
933
      Priv *p = (Priv*)o->user_data;
934 935
      flush_audio (o);
      flush_video (o);
936

937
      av_write_trailer (p->oc);
938

939 940 941 942
      if (p->video_st)
        close_video (p, p->oc, p->video_st);
      if (p->audio_st)
        close_audio (p, p->oc, p->audio_st);
Kevin Cozens's avatar
Kevin Cozens committed
943

944 945
      avio_closep (&p->oc->pb);
      avformat_free_context (p->oc);
946

947 948
      g_free (o->user_data);
      o->user_data = NULL;
Kevin Cozens's avatar
Kevin Cozens committed
949 950 951 952 953 954 955
    }

  G_OBJECT_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)))->finalize (object);
}


static void
956
gegl_op_class_init (GeglOpClass *klass)
Kevin Cozens's avatar
Kevin Cozens committed
957 958 959 960 961 962 963 964 965 966 967 968
{
  GeglOperationClass     *operation_class;
  GeglOperationSinkClass *sink_class;

  G_OBJECT_CLASS (klass)->finalize = finalize;

  operation_class = GEGL_OPERATION_CLASS (klass);
  sink_class      = GEGL_OPERATION_SINK_CLASS (klass);

  sink_class->process = process;
  sink_class->needs_full = TRUE;

969 970 971 972 973
  gegl_operation_class_set_keys (operation_class,
    "name"        , "gegl:ff-save",
    "categories"  , "output:video",
    "description" , _("FFmpeg video output sink"),
    NULL);
Kevin Cozens's avatar
Kevin Cozens committed
974 975
}

976
#endif