|
Packit |
bc1512 |
/* This file is an image processing operation for GEGL
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is free software; you can redistribute it and/or
|
|
Packit |
bc1512 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License as published by the Free Software Foundation; either
|
|
Packit |
bc1512 |
* version 3 of the License, or (at your option) any later version.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit |
bc1512 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
bc1512 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
bc1512 |
* Lesser General Public License for more details.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* Copyright 2003,2004,2007 Øyvind Kolås <pippin@gimp.org>
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "config.h"
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include <stdlib.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include <glib/gi18n-lib.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include <libswscale/swscale.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_chant_string (path, _("File"), "/tmp/fnord.mp4", _("Target path and filename, use '-' for stdout."))
|
|
Packit |
bc1512 |
gegl_chant_double (bitrate, _("Bitrate"), 0.0, 100000000.0, 800000.0, _("target bitrate"))
|
|
Packit |
bc1512 |
gegl_chant_double (fps, _("FPS"), 0.0, 100.0, 25, _("frames per second"))
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#else
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#define GEGL_CHANT_TYPE_SINK
|
|
Packit |
bc1512 |
#define GEGL_CHANT_C_FILE "ff-save.c"
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "gegl-chant.h"
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifdef HAVE_LIBAVFORMAT_AVFORMAT_H
|
|
Packit |
bc1512 |
#include <libavformat/avformat.h>
|
|
Packit |
bc1512 |
#else
|
|
Packit |
bc1512 |
#include <avformat.h>
|
|
Packit |
bc1512 |
#endif
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
typedef struct
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gdouble frame;
|
|
Packit |
bc1512 |
gdouble frames;
|
|
Packit |
bc1512 |
gdouble width;
|
|
Packit |
bc1512 |
gdouble height;
|
|
Packit |
bc1512 |
GeglBuffer *input;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
AVOutputFormat *fmt;
|
|
Packit |
bc1512 |
AVFormatContext *oc;
|
|
Packit |
bc1512 |
AVStream *video_st;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
AVFrame *picture, *tmp_picture;
|
|
Packit |
bc1512 |
uint8_t *video_outbuf;
|
|
Packit |
bc1512 |
int frame_count, video_outbuf_size;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/** the rest is for audio handling within oxide, note that the interface
|
|
Packit |
bc1512 |
* used passes all used functions in the oxide api through the reg_sym api
|
|
Packit |
bc1512 |
* of gggl, this means that the ops should be usable by other applications
|
|
Packit |
bc1512 |
* using gggl directly,. without needing to link with the oxide library
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
AVStream *audio_st;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
void *oxide_audio_instance;
|
|
Packit |
bc1512 |
/*< non NULL audio_query,. means audio present */
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
int32_t (*oxide_audio_query) (void *audio_instance,
|
|
Packit |
bc1512 |
uint32_t * sample_rate,
|
|
Packit |
bc1512 |
uint32_t * bits,
|
|
Packit |
bc1512 |
uint32_t * channels,
|
|
Packit |
bc1512 |
uint32_t * fragment_samples,
|
|
Packit |
bc1512 |
uint32_t * fragment_size);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* get audio samples for the current video frame, this should provide all
|
|
Packit |
bc1512 |
* audiosamples associated with the frame, frame centering on audio stream is
|
|
Packit |
bc1512 |
* undefined (FIXME:<<)
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
int32_t (*oxide_audio_get_fragment) (void *audio_instance, uint8_t * buf);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
uint32_t sample_rate;
|
|
Packit |
bc1512 |
uint32_t bits;
|
|
Packit |
bc1512 |
uint32_t channels;
|
|
Packit |
bc1512 |
uint32_t fragment_samples;
|
|
Packit |
bc1512 |
uint32_t fragment_size;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
uint8_t *fragment;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
int buffer_size;
|
|
Packit |
bc1512 |
int buffer_read_pos;
|
|
Packit |
bc1512 |
int buffer_write_pos;
|
|
Packit |
bc1512 |
uint8_t *buffer; /* optimal buffer size should be calculated,. preferably
|
|
Packit |
bc1512 |
run time,. no magic numbers needed for the filewrite
|
|
Packit |
bc1512 |
case, perhaps a tiny margin for ntsc since it has a
|
|
Packit |
bc1512 |
strange framerate */
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
int audio_outbuf_size;
|
|
Packit |
bc1512 |
int audio_input_frame_size;
|
|
Packit |
bc1512 |
int16_t *samples;
|
|
Packit |
bc1512 |
uint8_t *audio_outbuf;
|
|
Packit |
bc1512 |
} Priv;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#define DISABLE_AUDIO
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
init (GeglChantO *o)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
static gint inited = 0; /*< this is actually meant to be static, only to be done once */
|
|
Packit |
bc1512 |
Priv *p = (Priv*)o->chant_data;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p == NULL)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
p = g_new0 (Priv, 1);
|
|
Packit |
bc1512 |
o->chant_data = (void*) p;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!inited)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
av_register_all ();
|
|
Packit |
bc1512 |
avcodec_register_all ();
|
|
Packit |
bc1512 |
inited = 1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifndef DISABLE_AUDIO
|
|
Packit |
bc1512 |
p->oxide_audio_instance = gggl_op_sym (op, "oxide_audio_instance");
|
|
Packit |
bc1512 |
p->oxide_audio_query = gggl_op_sym (op, "oxide_audio_query()");
|
|
Packit |
bc1512 |
p->oxide_audio_get_fragment =
|
|
Packit |
bc1512 |
gggl_op_sym (op, "oxide_audio_get_fragment()");
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->oxide_audio_instance && p->oxide_audio_query)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
p->oxide_audio_query (p->oxide_audio_instance,
|
|
Packit |
bc1512 |
&p->sample_rate,
|
|
Packit |
bc1512 |
&p->bits,
|
|
Packit |
bc1512 |
&p->channels,
|
|
Packit |
bc1512 |
&p->fragment_samples, &p->fragment_size);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* FIXME: for now, the buffer is set to a size double that of a oxide
|
|
Packit |
bc1512 |
* provided fragment,. should be enough no matter how things are handled,
|
|
Packit |
bc1512 |
* but it should also be more than needed,. find out exact amount needed later
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!p->buffer)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
int size =
|
|
Packit |
bc1512 |
(p->sample_rate / p->fps) * p->channels * (p->bits / 8) * 2;
|
|
Packit |
bc1512 |
buffer_open (op, size);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!p->fragment)
|
|
Packit |
bc1512 |
p->fragment = gggl_op_calloc (op, 1, p->fragment_size);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
#endif
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void close_video (Priv *p,
|
|
Packit |
bc1512 |
AVFormatContext *oc,
|
|
Packit |
bc1512 |
AVStream *st);
|
|
Packit |
bc1512 |
void close_audio (Priv *p,
|
|
Packit |
bc1512 |
AVFormatContext *oc,
|
|
Packit |
bc1512 |
AVStream *st);
|
|
Packit |
bc1512 |
static int tfile (GeglChantO *self);
|
|
Packit |
bc1512 |
static void write_video_frame (GeglChantO *self,
|
|
Packit |
bc1512 |
AVFormatContext *oc,
|
|
Packit |
bc1512 |
AVStream *st);
|
|
Packit |
bc1512 |
static void write_audio_frame (GeglChantO *self,
|
|
Packit |
bc1512 |
AVFormatContext *oc,
|
|
Packit |
bc1512 |
AVStream *st);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#define STREAM_FRAME_RATE 25 /* 25 images/s */
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static int
|
|
Packit |
bc1512 |
buffer_used (Priv * p)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
int ret;
|
|
Packit |
bc1512 |
if (!p || !p->buffer_size || !p->buffer)
|
|
Packit |
bc1512 |
return -1;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->buffer_write_pos == p->buffer_read_pos)
|
|
Packit |
bc1512 |
return 0;
|
|
Packit |
bc1512 |
if (p->buffer_write_pos > p->buffer_read_pos)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
ret = p->buffer_write_pos - p->buffer_read_pos;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
ret = p->buffer_size - (p->buffer_read_pos - p->buffer_write_pos);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
return ret;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static int
|
|
Packit |
bc1512 |
buffer_unused (Priv * p)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
int ret;
|
|
Packit |
bc1512 |
ret = p->buffer_size - buffer_used (p) - 1; /* 1 byte for indicating full */
|
|
Packit |
bc1512 |
return ret;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifndef DISABLE_AUDIO
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
buffer_flush (Priv * p)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
if (!p->buffer)
|
|
Packit |
bc1512 |
return;
|
|
Packit |
bc1512 |
p->buffer_write_pos = 0;
|
|
Packit |
bc1512 |
p->buffer_read_pos = 0;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
buffer_open (GeglChantOperation *op, int size)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)op->priv;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->buffer)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "double init of buffer, eek!\n");
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p->buffer_size = size;
|
|
Packit |
bc1512 |
p->buffer = g_malloc (size);
|
|
Packit |
bc1512 |
buffer_flush (p);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
buffer_close (GeglChantOperation *op)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)op->priv;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!p->buffer)
|
|
Packit |
bc1512 |
return;
|
|
Packit |
bc1512 |
g_free (p->buffer);
|
|
Packit |
bc1512 |
p->buffer = NULL;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#endif
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static int
|
|
Packit |
bc1512 |
buffer_write (Priv * p, uint8_t * source, int count)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
int first_segment_size = 0;
|
|
Packit |
bc1512 |
int second_segment_size = 0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* check if we have room for the data in the buffer */
|
|
Packit |
bc1512 |
if (!p->buffer || buffer_unused (p) < count + 1)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "ff_save audio buffer full!! shouldn't happen\n");
|
|
Packit |
bc1512 |
return -1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* calculate size of segments to write */
|
|
Packit |
bc1512 |
first_segment_size = p->buffer_size - p->buffer_write_pos;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->buffer_read_pos > p->buffer_write_pos)
|
|
Packit |
bc1512 |
first_segment_size = p->buffer_read_pos - p->buffer_write_pos;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (first_segment_size >= count)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
first_segment_size = count;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
second_segment_size = count - first_segment_size;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
memcpy (p->buffer + p->buffer_write_pos, source, first_segment_size);
|
|
Packit |
bc1512 |
p->buffer_write_pos += first_segment_size;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->buffer_write_pos == p->buffer_size)
|
|
Packit |
bc1512 |
p->buffer_write_pos = 0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (second_segment_size)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
memcpy (p->buffer + p->buffer_write_pos, source + first_segment_size,
|
|
Packit |
bc1512 |
second_segment_size);
|
|
Packit |
bc1512 |
p->buffer_write_pos = second_segment_size;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return first_segment_size + second_segment_size;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#if 0
|
|
Packit |
bc1512 |
. = unused byte
|
|
Packit |
bc1512 |
# = used byte
|
|
Packit |
bc1512 |
all sizes are specified in contiguous bytes of memory
|
|
Packit |
bc1512 |
__write_pos / __read_pos
|
|
Packit |
bc1512 |
//
|
|
Packit |
bc1512 |
|................................... | empty buffer
|
|
Packit |
bc1512 |
\ _________________________________ /
|
|
Packit |
bc1512 |
size_ / __read_pos __write_pos / /|........
|
|
Packit |
bc1512 |
#################..........|
|
|
Packit |
bc1512 |
\ ______________ / used ()_ / __write_pos __read_pos / /|
|
|
Packit |
bc1512 |
############..................#####|
|
|
Packit |
bc1512 |
\______________ / unused ()_ / ___write_pos / __read_pos / /|
|
|
Packit |
bc1512 |
#################.#################| full buffer
|
|
Packit |
bc1512 |
#endif
|
|
Packit |
bc1512 |
static int
|
|
Packit |
bc1512 |
buffer_read (Priv * p, uint8_t * dest, int count)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
int first_segment_size = 0;
|
|
Packit |
bc1512 |
int second_segment_size = 0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* check if we have enough data to fulfil request */
|
|
Packit |
bc1512 |
if (!p->buffer || buffer_used (p) < count)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "ff_save audio buffer doesn't have enough data\n");
|
|
Packit |
bc1512 |
return -1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* calculate size of segments to write */
|
|
Packit |
bc1512 |
first_segment_size = p->buffer_size - p->buffer_read_pos;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->buffer_write_pos > p->buffer_read_pos)
|
|
Packit |
bc1512 |
first_segment_size = p->buffer_write_pos - p->buffer_read_pos;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (first_segment_size >= count)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
first_segment_size = count;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
second_segment_size = count - first_segment_size;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
memcpy (dest, p->buffer + p->buffer_read_pos, first_segment_size);
|
|
Packit |
bc1512 |
p->buffer_read_pos += first_segment_size;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->buffer_read_pos == p->buffer_size)
|
|
Packit |
bc1512 |
p->buffer_read_pos = 0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (second_segment_size)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
memcpy (dest + first_segment_size, p->buffer + p->buffer_read_pos,
|
|
Packit |
bc1512 |
second_segment_size);
|
|
Packit |
bc1512 |
p->buffer_read_pos = second_segment_size;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return first_segment_size + second_segment_size;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifndef DISABLE_AUDIO
|
|
Packit |
bc1512 |
/* add an audio output stream */
|
|
Packit |
bc1512 |
static AVStream *
|
|
Packit |
bc1512 |
add_audio_stream (GeglChantOperation *op, AVFormatContext * oc, int codec_id)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)op->priv;
|
|
Packit |
bc1512 |
AVCodecContext *c;
|
|
Packit |
bc1512 |
AVStream *st;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p = NULL;
|
|
Packit |
bc1512 |
st = av_new_stream (oc, 1);
|
|
Packit |
bc1512 |
if (!st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "Could not alloc stream\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c = st->codec;
|
|
Packit |
bc1512 |
c->codec_id = codec_id;
|
|
Packit |
bc1512 |
c->codec_type = CODEC_TYPE_AUDIO;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c->bit_rate = 64000;
|
|
Packit |
bc1512 |
c->sample_rate = 44100;
|
|
Packit |
bc1512 |
c->channels = 2;
|
|
Packit |
bc1512 |
return st;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
#endif
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
open_audio (Priv * p, AVFormatContext * oc, AVStream * st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
AVCodecContext *c;
|
|
Packit |
bc1512 |
AVCodec *codec;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c = st->codec;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* find the audio encoder */
|
|
Packit |
bc1512 |
codec = avcodec_find_encoder (c->codec_id);
|
|
Packit |
bc1512 |
if (!codec)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "codec not found\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* open it */
|
|
Packit |
bc1512 |
if (avcodec_open2 (c, codec, NULL) < 0)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "could not open codec\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p->audio_outbuf_size = 10000;
|
|
Packit |
bc1512 |
p->audio_outbuf = malloc (p->audio_outbuf_size);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* ugly hack for PCM codecs (will be removed ASAP with new PCM
|
|
Packit |
bc1512 |
support to compute the input frame size in samples */
|
|
Packit |
bc1512 |
if (c->frame_size <= 1)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "eeko\n");
|
|
Packit |
bc1512 |
p->audio_input_frame_size = p->audio_outbuf_size / c->channels;
|
|
Packit |
bc1512 |
switch (st->codec->codec_id)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
case CODEC_ID_PCM_S16LE:
|
|
Packit |
bc1512 |
case CODEC_ID_PCM_S16BE:
|
|
Packit |
bc1512 |
case CODEC_ID_PCM_U16LE:
|
|
Packit |
bc1512 |
case CODEC_ID_PCM_U16BE:
|
|
Packit |
bc1512 |
p->audio_input_frame_size >>= 1;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
default:
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
p->audio_input_frame_size = c->frame_size;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
/*audio_input_frame_size = 44100/25;*/
|
|
Packit |
bc1512 |
p->samples = malloc (p->audio_input_frame_size * 2 * c->channels);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
void
|
|
Packit |
bc1512 |
write_audio_frame (GeglChantO *op, AVFormatContext * oc, AVStream * st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)op->chant_data;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
AVCodecContext *c;
|
|
Packit |
bc1512 |
AVPacket pkt;
|
|
Packit |
bc1512 |
av_init_packet (&pkt);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c = st->codec;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*fprintf (stderr, "going to grab %i\n", p->fragment_size);*/
|
|
Packit |
bc1512 |
if (p->oxide_audio_get_fragment (p->oxide_audio_instance,
|
|
Packit |
bc1512 |
p->fragment) == (signed) p->fragment_size)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
buffer_write (p, p->fragment, p->fragment_size);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
while (buffer_used (p) >= p->audio_input_frame_size * 2 * c->channels)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
buffer_read (p, (uint8_t *) p->samples,
|
|
Packit |
bc1512 |
p->audio_input_frame_size * 2 * c->channels);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
pkt.size = avcodec_encode_audio (c, p->audio_outbuf,
|
|
Packit |
bc1512 |
p->audio_outbuf_size, p->samples);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
pkt.pts = c->coded_frame->pts;
|
|
Packit |
bc1512 |
pkt.flags |= AV_PKT_FLAG_KEY;
|
|
Packit |
bc1512 |
pkt.stream_index = st->index;
|
|
Packit |
bc1512 |
pkt.data = p->audio_outbuf;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (av_write_frame (oc, &pkt) != 0)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "Error while writing audio frame\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*p->audio_get_frame (samples, audio_input_frame_size, c->channels);*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
void
|
|
Packit |
bc1512 |
close_audio (Priv * p, AVFormatContext * oc, AVStream * st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
avcodec_close (st->codec);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
av_free (p->samples);
|
|
Packit |
bc1512 |
av_free (p->audio_outbuf);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* add a video output stream */
|
|
Packit |
bc1512 |
static AVStream *
|
|
Packit |
bc1512 |
add_video_stream (GeglChantO *op, AVFormatContext * oc, int codec_id)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)op->chant_data;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
AVCodecContext *c;
|
|
Packit |
bc1512 |
AVStream *st;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
st = av_new_stream (oc, 0);
|
|
Packit |
bc1512 |
if (!st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "Could not alloc stream %p %p %i\n", op, oc, codec_id);
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c = st->codec;
|
|
Packit |
bc1512 |
c->codec_id = codec_id;
|
|
Packit |
bc1512 |
c->codec_type = AVMEDIA_TYPE_VIDEO;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* put sample propeters */
|
|
Packit |
bc1512 |
c->bit_rate = op->bitrate;
|
|
Packit |
bc1512 |
/* resolution must be a multiple of two */
|
|
Packit |
bc1512 |
c->width = p->width;
|
|
Packit |
bc1512 |
c->height = p->height;
|
|
Packit |
bc1512 |
/* frames per second */
|
|
Packit |
bc1512 |
/*c->frame_rate = op->fps;
|
|
Packit |
bc1512 |
c->frame_rate_base = 1;*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#if LIBAVCODEC_BUILD >= 4754
|
|
Packit |
bc1512 |
c->time_base=(AVRational){1, op->fps};
|
|
Packit |
bc1512 |
#else
|
|
Packit |
bc1512 |
c->frame_rate=op->fps;
|
|
Packit |
bc1512 |
c->frame_rate_base=1;
|
|
Packit |
bc1512 |
#endif
|
|
Packit |
bc1512 |
c->pix_fmt = PIX_FMT_YUV420P;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
|
|
Packit |
bc1512 |
if (c->codec_id == CODEC_ID_MPEG2VIDEO)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* just for testing, we also add B frames */
|
|
Packit |
bc1512 |
/*c->max_b_frames = 2;*/
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
/* if (!strcmp (oc->oformat->name, "mp4") ||
|
|
Packit |
bc1512 |
!strcmp (oc->oformat->name, "3gp"))
|
|
Packit |
bc1512 |
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
return st;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static AVFrame *
|
|
Packit |
bc1512 |
alloc_picture (int pix_fmt, int width, int height)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
AVFrame *picture;
|
|
Packit |
bc1512 |
uint8_t *picture_buf;
|
|
Packit |
bc1512 |
int size;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
picture = avcodec_alloc_frame ();
|
|
Packit |
bc1512 |
if (!picture)
|
|
Packit |
bc1512 |
return NULL;
|
|
Packit |
bc1512 |
size = avpicture_get_size (pix_fmt, width, height);
|
|
Packit |
bc1512 |
picture_buf = malloc (size);
|
|
Packit |
bc1512 |
if (!picture_buf)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
av_free (picture);
|
|
Packit |
bc1512 |
return NULL;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
avpicture_fill ((AVPicture *) picture, picture_buf, pix_fmt, width, height);
|
|
Packit |
bc1512 |
return picture;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
open_video (Priv * p, AVFormatContext * oc, AVStream * st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
AVCodec *codec;
|
|
Packit |
bc1512 |
AVCodecContext *c;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c = st->codec;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* find the video encoder */
|
|
Packit |
bc1512 |
codec = avcodec_find_encoder (c->codec_id);
|
|
Packit |
bc1512 |
if (!codec)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "codec not found\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* open the codec */
|
|
Packit |
bc1512 |
if (avcodec_open (c, codec) < 0)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "could not open codec\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p->video_outbuf = NULL;
|
|
Packit |
bc1512 |
if (!(oc->oformat->flags & AVFMT_RAWPICTURE))
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* allocate output buffer */
|
|
Packit |
bc1512 |
/* XXX: API change will be done */
|
|
Packit |
bc1512 |
p->video_outbuf_size = 200000;
|
|
Packit |
bc1512 |
p->video_outbuf = malloc (p->video_outbuf_size);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* allocate the encoded raw picture */
|
|
Packit |
bc1512 |
p->picture = alloc_picture (c->pix_fmt, c->width, c->height);
|
|
Packit |
bc1512 |
if (!p->picture)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "Could not allocate picture\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* if the output format is not YUV420P, then a temporary YUV420P
|
|
Packit |
bc1512 |
picture is needed too. It is then converted to the required
|
|
Packit |
bc1512 |
output format */
|
|
Packit |
bc1512 |
p->tmp_picture = NULL;
|
|
Packit |
bc1512 |
if (c->pix_fmt != PIX_FMT_RGB24)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
p->tmp_picture = alloc_picture (PIX_FMT_RGB24, c->width, c->height);
|
|
Packit |
bc1512 |
if (!p->tmp_picture)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "Could not allocate temporary picture\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
close_video (Priv * p, AVFormatContext * oc, AVStream * st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
avcodec_close (st->codec);
|
|
Packit |
bc1512 |
av_free (p->picture->data[0]);
|
|
Packit |
bc1512 |
av_free (p->picture);
|
|
Packit |
bc1512 |
if (p->tmp_picture)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
av_free (p->tmp_picture->data[0]);
|
|
Packit |
bc1512 |
av_free (p->tmp_picture);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
av_free (p->video_outbuf);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "string.h"
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* prepare a dummy image */
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
fill_yuv_image (GeglChantO *op,
|
|
Packit |
bc1512 |
AVFrame *pict, int frame_index, int width, int height)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)op->chant_data;
|
|
Packit |
bc1512 |
/*memcpy (pict->data[0],
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
op->input_pad[0]->data,
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
op->input_pad[0]->width * op->input_pad[0]->height * 3);*/
|
|
Packit |
bc1512 |
GeglRectangle rect={0,0,width,height};
|
|
Packit |
bc1512 |
gegl_buffer_get (p->input, &rect, 1.0, babl_format ("R'G'B' u8"), pict->data[0], GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
write_video_frame (GeglChantO *op,
|
|
Packit |
bc1512 |
AVFormatContext *oc, AVStream *st)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)op->chant_data;
|
|
Packit |
bc1512 |
int out_size, ret;
|
|
Packit |
bc1512 |
AVCodecContext *c;
|
|
Packit |
bc1512 |
AVFrame *picture_ptr;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
c = st->codec;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (c->pix_fmt != PIX_FMT_RGB24)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
struct SwsContext *img_convert_ctx;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* as we only generate a RGB24 picture, we must convert it
|
|
Packit |
bc1512 |
to the codec pixel format if needed */
|
|
Packit |
bc1512 |
fill_yuv_image (op, p->tmp_picture, p->frame_count, c->width,
|
|
Packit |
bc1512 |
c->height);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
img_convert_ctx = sws_getContext(c->width, c->height, c->pix_fmt,
|
|
Packit |
bc1512 |
c->width, c->height, PIX_FMT_RGB24,
|
|
Packit |
bc1512 |
SWS_BICUBIC, NULL, NULL, NULL);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (img_convert_ctx == NULL)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf(stderr, "ff_save: Cannot initialize conversion context.");
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
sws_scale(img_convert_ctx,
|
|
Packit |
bc1512 |
p->tmp_picture->data,
|
|
Packit |
bc1512 |
p->tmp_picture->linesize,
|
|
Packit |
bc1512 |
0,
|
|
Packit |
bc1512 |
c->height,
|
|
Packit |
bc1512 |
p->picture->data,
|
|
Packit |
bc1512 |
p->picture->linesize);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fill_yuv_image (op, p->picture, p->frame_count, c->width, c->height);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
picture_ptr = p->picture;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (oc->oformat->flags & AVFMT_RAWPICTURE)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* raw video case. The API will change slightly in the near
|
|
Packit |
bc1512 |
future for that */
|
|
Packit |
bc1512 |
AVPacket pkt;
|
|
Packit |
bc1512 |
av_init_packet (&pkt);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
pkt.flags |= AV_PKT_FLAG_KEY;
|
|
Packit |
bc1512 |
pkt.stream_index = st->index;
|
|
Packit |
bc1512 |
pkt.data = (uint8_t *) picture_ptr;
|
|
Packit |
bc1512 |
pkt.size = sizeof (AVPicture);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
ret = av_write_frame (oc, &pkt);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* encode the image */
|
|
Packit |
bc1512 |
out_size =
|
|
Packit |
bc1512 |
avcodec_encode_video (c,
|
|
Packit |
bc1512 |
p->video_outbuf,
|
|
Packit |
bc1512 |
p->video_outbuf_size, picture_ptr);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* if zero size, it means the image was buffered */
|
|
Packit |
bc1512 |
if (out_size != 0)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
AVPacket pkt;
|
|
Packit |
bc1512 |
av_init_packet (&pkt);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
pkt.pts = c->coded_frame->pts;
|
|
Packit |
bc1512 |
if (c->coded_frame->key_frame)
|
|
Packit |
bc1512 |
pkt.flags |= AV_PKT_FLAG_KEY;
|
|
Packit |
bc1512 |
pkt.stream_index = st->index;
|
|
Packit |
bc1512 |
pkt.data = p->video_outbuf;
|
|
Packit |
bc1512 |
pkt.size = out_size;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* write the compressed frame in the media file */
|
|
Packit |
bc1512 |
ret = av_write_frame (oc, &pkt);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
ret = 0;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
if (ret != 0)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "Error while writing video frame\n");
|
|
Packit |
bc1512 |
exit (1);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
p->frame_count++;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static int
|
|
Packit |
bc1512 |
tfile (GeglChantO *self)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)self->chant_data;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p->fmt = av_guess_format (NULL, self->path, NULL);
|
|
Packit |
bc1512 |
if (!p->fmt)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr,
|
|
Packit |
bc1512 |
"ff_save couldn't deduce outputformat from file extension: using MPEG.\n%s",
|
|
Packit |
bc1512 |
"");
|
|
Packit |
bc1512 |
p->fmt = av_guess_format ("mpeg", NULL, NULL);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
p->oc = avformat_alloc_context ();/*g_malloc (sizeof (AVFormatContext));*/
|
|
Packit |
bc1512 |
if (!p->oc)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "memory error\n%s", "");
|
|
Packit |
bc1512 |
return -1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p->oc->oformat = p->fmt;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
snprintf (p->oc->filename, sizeof (p->oc->filename), "%s", self->path);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p->video_st = NULL;
|
|
Packit |
bc1512 |
p->audio_st = NULL;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->fmt->video_codec != CODEC_ID_NONE)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
p->video_st = add_video_stream (self, p->oc, p->fmt->video_codec);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
if (p->oxide_audio_query && p->fmt->audio_codec != CODEC_ID_NONE)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/*XXX: FOO p->audio_st = add_audio_stream (op, p->oc, p->fmt->audio_codec);*/
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (av_set_parameters (p->oc, NULL) < 0)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "Invalid output format propeters\n%s", "");
|
|
Packit |
bc1512 |
return -1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
dump_format (p->oc, 0, self->path, 1);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->video_st)
|
|
Packit |
bc1512 |
open_video (p, p->oc, p->video_st);
|
|
Packit |
bc1512 |
if (p->audio_st)
|
|
Packit |
bc1512 |
open_audio (p, p->oc, p->audio_st);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (url_fopen (&p->oc->pb, self->path, URL_WRONLY) < 0)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
fprintf (stderr, "couldn't open '%s'\n", self->path);
|
|
Packit |
bc1512 |
return -1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
av_write_header (p->oc);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return 0;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#if 0
|
|
Packit |
bc1512 |
static int
|
|
Packit |
bc1512 |
filechanged (GeglChantOperation *op, const char *att)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
init (op);
|
|
Packit |
bc1512 |
return 0;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
#endif
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static gboolean
|
|
Packit |
bc1512 |
process (GeglOperation *operation,
|
|
Packit |
bc1512 |
GeglBuffer *input,
|
|
Packit |
bc1512 |
const GeglRectangle *result,
|
|
Packit |
bc1512 |
gint level)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
static gint inited = 0;
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit |
bc1512 |
Priv *p = (Priv*)o->chant_data;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
g_assert (input);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p == NULL)
|
|
Packit |
bc1512 |
init (o);
|
|
Packit |
bc1512 |
p = (Priv*)o->chant_data;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
p->width = result->width;
|
|
Packit |
bc1512 |
p->height = result->height;
|
|
Packit |
bc1512 |
p->input = input;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (!inited)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
tfile (o);
|
|
Packit |
bc1512 |
inited = 1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
write_video_frame (o, p->oc, p->video_st);
|
|
Packit |
bc1512 |
if (p->audio_st)
|
|
Packit |
bc1512 |
write_audio_frame (o, p->oc, p->audio_st);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return TRUE;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
finalize (GObject *object)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
|
|
Packit |
bc1512 |
if (o->chant_data)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
Priv *p = (Priv*)o->chant_data;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (p->oc)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gint i;
|
|
Packit |
bc1512 |
if (p->video_st)
|
|
Packit |
bc1512 |
close_video (p, p->oc, p->video_st);
|
|
Packit |
bc1512 |
if (p->audio_st)
|
|
Packit |
bc1512 |
close_audio (p, p->oc, p->audio_st);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
av_write_trailer (p->oc);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (i = 0; i < p->oc->nb_streams; i++)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
av_freep (&p->oc->streams[i]);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
url_fclose (&p->oc->pb);
|
|
Packit |
bc1512 |
free (p->oc);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
g_free (o->chant_data);
|
|
Packit |
bc1512 |
o->chant_data = NULL;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
G_OBJECT_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)))->finalize (object);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglOperationClass *operation_class;
|
|
Packit |
bc1512 |
GeglOperationSinkClass *sink_class;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
G_OBJECT_CLASS (klass)->finalize = finalize;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit |
bc1512 |
sink_class = GEGL_OPERATION_SINK_CLASS (klass);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
sink_class->process = process;
|
|
Packit |
bc1512 |
sink_class->needs_full = TRUE;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_operation_class_set_keys (operation_class,
|
|
Packit |
bc1512 |
"name" , "gegl:ff-save",
|
|
Packit |
bc1512 |
"categories" , "output:video",
|
|
Packit |
bc1512 |
"description" , _("FFmpeg video output sink"),
|
|
Packit |
bc1512 |
NULL);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#endif
|