Commit 73adf254 authored by Kevin Cozens's avatar Kevin Cozens

Updated to new chanting API.

* operations/io/ff-load.c:
* operations/workshop/ff-save.c:
* operations/workshop/gluas.c:
* operations/workshop/mblur.c: Updated to new chanting API.

svn path=/trunk/; revision=2039
parent 5775f42d
2008-02-17 Kevin Cozens <kcozens@cvs.gnome.org>
* operations/io/ff-load.c:
* operations/workshop/ff-save.c:
* operations/workshop/gluas.c:
* operations/workshop/mblur.c: Updated to new chanting API.
2008-02-17 Øyvind Kolås <pippin@gimp.org>
* operations/workshop/difference-of-gaussians.c: moved ..
......
......@@ -15,23 +15,17 @@
*
* Copyright 2003, 2006 yvind Kols <pippin@gimp.org>
*/
#if GEGL_CHANT_PROPERTIES
#ifdef GEGL_CHANT_PROPERTIES
gegl_chant_path (path, "/home/pippin/ed.avi", "Path of file to load.")
gegl_chant_int (frame, 0, 1000000, 0, "frame number")
gegl_chant_path (path, "File", "", "Path of file to load.")
gegl_chant_int (frame, "Frame", 0, 1000000, 0, "frame number")
#else
#define GEGL_CHANT_SOURCE
#define GEGL_CHANT_NAME ff_load
#define GEGL_CHANT_DESCRIPTION "FFmpeg video frame importer."
#define GEGL_CHANT_SELF "ff-load.c"
#define GEGL_CHANT_CATEGORIES "input:video"
#define GEGL_CHANT_INIT
#define GEGL_CHANT_CLASS_INIT
#include "gegl-old-chant.h"
#define GEGL_CHANT_TYPE_SOURCE
#define GEGL_CHANT_C_FILE "ff-load.c"
#include "gegl-chant.h"
#include <errno.h>
#include <ffmpeg/avformat.h>
......@@ -85,15 +79,15 @@ print_error (const char *filename, int err)
}
static void
init (GeglChantOperation *operation)
init (GeglChantO *o)
{
GeglChantOperation *self = GEGL_CHANT_OPERATION (operation);
Priv *p = (Priv*)self->priv;
static gint inited = 0; /*< this is actually meant to be static, only to be done once */
static gint inited = 0; /*< this is actually meant to be static, only to be done once */
Priv *p = (Priv*)o->chant_data;
if (p==NULL)
{
p = g_malloc0 (sizeof (Priv));
self->priv = (void*) p;
p = g_new0 (Priv, 1);
o->chant_data = (void*) p;
}
p->width = 320;
......@@ -112,9 +106,9 @@ init (GeglChantOperation *operation)
/* FIXME: probably some more stuff to free here */
static void
ff_cleanup (GeglChantOperation *operation)
ff_cleanup (GeglChantO *o)
{
Priv *p = (Priv*)operation->priv;
Priv *p = (Priv*)o->chant_data;
if (p)
{
if (p->codec_name)
......@@ -137,45 +131,131 @@ ff_cleanup (GeglChantOperation *operation)
}
}
static glong
prev_keyframe (Priv *priv, glong frame)
{
/* no way to detect previous keyframe at the moment for ffmpeg,
so we'll just return 0, the first, and a forced reload happens
if needed
*/
return 0;
}
static void
finalize (GObject *object)
static int
decode_frame (GeglOperation *operation,
glong frame)
{
GeglChantOperation *self = GEGL_CHANT_OPERATION (object);
if (self->priv)
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
Priv *p = (Priv*)o->chant_data;
glong prevframe = p->prevframe;
glong decodeframe; /*< frame to be requested decoded */
if (frame >= p->frames)
{
ff_cleanup (self);
g_free (self->priv);
self->priv = NULL;
frame = p->frames - 1;
}
G_OBJECT_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)))->finalize (object);
if (frame < 0)
{
frame = 0;
}
if (frame == prevframe)
{
return 0;
}
/* figure out which frame we should start decoding at */
if (frame == prevframe + 1)
{
decodeframe = prevframe + 1;
}
else
{
decodeframe = prev_keyframe (p, frame);
if (prevframe > decodeframe && prevframe < frame)
decodeframe = prevframe + 1;
}
if (decodeframe < prevframe)
{
/* seeking backwards, since it ffmpeg doesn't allow us,. we'll reload the file */
g_free (p->loadedfilename);
p->loadedfilename = NULL;
init (operation);
}
while (decodeframe <= frame)
{
int got_picture = 0;
do
{
int decoded_bytes;
if (p->coded_bytes <= 0)
{
do
{
if (av_read_packet (p->ic, &p->pkt) < 0)
{
fprintf (stderr, "av_read_packet failed for %s\n",
o->path);
return -1;
}
}
while (p->pkt.stream_index != p->video_stream);
p->coded_bytes = p->pkt.size;
p->coded_buf = p->pkt.data;
}
decoded_bytes =
avcodec_decode_video (p->video_st->codec, p->lavc_frame,
&got_picture, p->coded_buf, p->coded_bytes);
if (decoded_bytes < 0)
{
fprintf (stderr, "avcodec_decode_video failed for %s\n",
o->path);
return -1;
}
p->coded_buf += decoded_bytes;
p->coded_bytes -= decoded_bytes;
}
while (!got_picture);
decodeframe++;
}
p->prevframe = frame;
return 0;
}
static void
prepare (GeglOperation *operation)
{
GeglChantOperation *self = GEGL_CHANT_OPERATION (operation);
Priv *p= (Priv*)self->priv;
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
Priv *p = (Priv*)o->chant_data;
g_assert (o->chant_data != NULL);
gegl_operation_set_format (operation, "output", babl_format ("R'G'B'A u8"));
if (!p->loadedfilename ||
strcmp (p->loadedfilename, self->path))
strcmp (p->loadedfilename, o->path))
{
gint i;
gint err;
ff_cleanup (self);
err = av_open_input_file (&p->ic, self->path, NULL, 0, NULL);
ff_cleanup (o);
err = av_open_input_file (&p->ic, o->path, NULL, 0, NULL);
if (err < 0)
{
print_error (self->path, err);
print_error (o->path, err);
}
err = av_find_stream_info (p->ic);
if (err < 0)
{
g_warning ("ff-load: error finding stream info for %s", self->path);
g_warning ("ff-load: error finding stream info for %s", o->path);
return;
}
......@@ -236,110 +316,21 @@ prepare (GeglOperation *operation)
if (p->loadedfilename)
g_free (p->loadedfilename);
p->loadedfilename = g_strdup (self->path);
p->loadedfilename = g_strdup (o->path);
p->prevframe = -1;
p->coded_bytes = 0;
p->coded_buf = NULL;
}
}
static glong
prev_keyframe (Priv *priv, glong frame)
{
/* no way to detect previous keyframe at the moment for ffmpeg,
so we'll just return 0, the first, and a forced reload happens
if needed
*/
return 0;
}
static int
decode_frame (GeglChantOperation *op,
glong frame)
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
Priv *p = (Priv*)op->priv;
glong prevframe = p->prevframe;
glong decodeframe; /*< frame to be requested decoded */
if (frame >= p->frames)
{
frame = p->frames - 1;
}
if (frame < 0)
{
frame = 0;
}
if (frame == prevframe)
{
return 0;
}
/* figure out which frame we should start decoding at */
if (frame == prevframe + 1)
{
decodeframe = prevframe + 1;
}
else
{
decodeframe = prev_keyframe (p, frame);
if (prevframe > decodeframe && prevframe < frame)
decodeframe = prevframe + 1;
}
if (decodeframe < prevframe)
{
/* seeking backwards, since it ffmpeg doesn't allow us,. we'll reload the file */
g_free (p->loadedfilename);
p->loadedfilename = NULL;
init (op);
}
while (decodeframe <= frame)
{
int got_picture = 0;
do
{
int decoded_bytes;
if (p->coded_bytes <= 0)
{
do
{
if (av_read_packet (p->ic, &p->pkt) < 0)
{
fprintf (stderr, "av_read_packet failed for %s\n",
op->path);
return -1;
}
}
while (p->pkt.stream_index != p->video_stream);
p->coded_bytes = p->pkt.size;
p->coded_buf = p->pkt.data;
}
decoded_bytes =
avcodec_decode_video (p->video_st->codec, p->lavc_frame,
&got_picture, p->coded_buf, p->coded_bytes);
if (decoded_bytes < 0)
{
fprintf (stderr, "avcodec_decode_video failed for %s\n",
op->path);
return -1;
}
p->coded_buf += decoded_bytes;
p->coded_bytes -= decoded_bytes;
}
while (!got_picture);
decodeframe++;
}
p->prevframe = frame;
return 0;
GeglRectangle result = {0,0,320,200};
Priv *p = (Priv*)GEGL_CHANT_PROPERTIES (operation)->chant_data;
result.width = p->width;
result.height = p->height;
return result;
}
static gboolean
......@@ -347,11 +338,11 @@ process (GeglOperation *operation,
GeglBuffer *output,
const GeglRectangle *result)
{
GeglChantOperation *self = GEGL_CHANT_OPERATION (operation);
Priv *p = (Priv*)self->priv;
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
Priv *p = (Priv*)o->chant_data;
{
if (p->ic && !decode_frame (self, self->frame))
if (p->ic && !decode_frame (operation, o->frame))
{
guchar *buf;
gint pxsize;
......@@ -401,22 +392,46 @@ process (GeglOperation *operation,
return TRUE;
}
static GeglRectangle
get_bounding_box (GeglOperation *operation)
static void
finalize (GObject *object)
{
GeglRectangle result = {0,0,320,200};
Priv *p = (Priv*)GEGL_CHANT_OPERATION (operation)->priv;
result.width = p->width;
result.height = p->height;
return result;
GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
if (o->chant_data)
{
Priv *p = (Priv*)o->chant_data;
g_free (p->loadedfilename);
g_free (p->fourcc);
g_free (p->codec_name);
g_free (o->chant_data);
o->chant_data = NULL;
}
G_OBJECT_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)))->finalize (object);
}
static void class_init (GeglOperationClass *operation_class)
static void
operation_class_init (GeglChantClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (operation_class);
GeglOperationClass *operation_class;
GeglOperationSourceClass *source_class;
gobject_class->finalize = finalize;
G_OBJECT_CLASS (klass)->finalize = finalize;
operation_class = GEGL_OPERATION_CLASS (klass);
source_class = GEGL_OPERATION_SOURCE_CLASS (klass);
source_class->process = process;
operation_class->get_bounding_box = get_bounding_box;
operation_class->prepare = prepare;
operation_class->attach = init;
operation_class->name = "ff-load";
operation_class->categories = "input:video";
operation_class->description = "FFmpeg video frame importer.";
}
#endif
......@@ -15,24 +15,18 @@
*
* Copyright 2003,2004,2007 Øyvind Kolås <pippin@gimp.org>
*/
#if GEGL_CHANT_PROPERTIES
#ifdef GEGL_CHANT_PROPERTIES
gegl_chant_string (path, "/tmp/fnord.mp4", "Target path and filename, use '-' for stdout.")
gegl_chant_double (bitrate, 0.0, 100000000.0, 800000.0, "target bitrate")
gegl_chant_double (fps, 0.0, 100.0, 25, "frames per second")
gegl_chant_string (path, "File", "/tmp/fnord.mp4", "Target path and filename, use '-' for stdout.")
gegl_chant_double (bitrate, "Bitrate", 0.0, 100000000.0, 800000.0, "target bitrate")
gegl_chant_double (fps, "FPS", 0.0, 100.0, 25, "frames per second")
#else
#define GEGL_CHANT_NAME ff_save
#define GEGL_CHANT_SELF "ff-save.c"
#define GEGL_CHANT_DESCRIPTION "FFmpeg video output sink"
#define GEGL_CHANT_CATEGORIES "output:video"
#define GEGL_CHANT_TYPE_SINK
#define GEGL_CHANT_C_FILE "ff-save.c"
#define GEGL_CHANT_SINK
#define GEGL_CHANT_INIT
#define GEGL_CHANT_CLASS_INIT
#include "gegl-old-chant.h"
#include "gegl-chant.h"
#include "ffmpeg/avformat.h"
typedef struct
......@@ -47,12 +41,10 @@ typedef struct
AVFormatContext *oc;
AVStream *video_st;
AVFrame *picture, *tmp_picture;
uint8_t *video_outbuf;
int frame_count, video_outbuf_size;
/** 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
......@@ -61,7 +53,7 @@ typedef struct
AVStream *audio_st;
void *oxide_audio_instance;
void *oxide_audio_instance;
/*< non NULL audio_query,. means audio present */
int32_t (*oxide_audio_query) (void *audio_instance,
......@@ -102,16 +94,16 @@ typedef struct
#define DISABLE_AUDIO
static void
init (GeglChantOperation *operation)
static void
init (GeglChantO *o)
{
GeglChantOperation *self = GEGL_CHANT_OPERATION (operation);
Priv *p = (Priv*)self->priv;
static gint inited = 0; /*< this is actually meant to be static, only to be done once */
if (p==NULL)
static gint inited = 0; /*< this is actually meant to be static, only to be done once */
Priv *p = (Priv*)o->chant_data;
if (p == NULL)
{
p = g_malloc0 (sizeof (Priv));
self->priv = (void*) p;
p = g_new0 (Priv, 1);
o->chant_data = (void*) p;
}
if (!inited)
......@@ -142,7 +134,7 @@ init (GeglChantOperation *operation)
if (!p->buffer)
{
int size =
int size =
(p->sample_rate / p->fps) * p->channels * (p->bits / 8) * 2;
buffer_open (op, size);
}
......@@ -153,90 +145,21 @@ init (GeglChantOperation *operation)
#endif
}
static void close_video (Priv *p,
AVFormatContext *oc,
AVStream *st);
void close_audio (Priv *p,
AVFormatContext *oc,
AVStream *st);
static int tfile (GeglChantOperation *self);
static void write_video_frame (GeglChantOperation *self,
AVFormatContext *oc,
AVStream *st);
static void write_audio_frame (GeglChantOperation *self,
AVFormatContext *oc,
AVStream *st);
static void
finalize (GObject *object)
{
GeglChantOperation *self = GEGL_CHANT_OPERATION (object);
if (self->priv)
{
Priv *p = (Priv*)self->priv;
if (p->oc)
{
gint i;
if (p->video_st)
close_video (p, p->oc, p->video_st);
if (p->audio_st)
close_audio (p, p->oc, p->audio_st);
av_write_trailer (p->oc);
for (i = 0; i < p->oc->nb_streams; i++)
{
av_freep (&p->oc->streams[i]);
}
url_fclose (&p->oc->pb);
free (p->oc);
}
g_free (self->priv);
self->priv = NULL;
}
G_OBJECT_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)))->finalize (object);
}
static gboolean
process (GeglOperation *operation,
GeglBuffer *input,
const GeglRectangle *result)
{
GeglChantOperation *self = GEGL_CHANT_OPERATION (operation);
Priv *p = (Priv*)self->priv;
static gint inited = 0;
static void close_video (Priv *p,
AVFormatContext *oc,
AVStream *st);
void close_audio (Priv *p,
AVFormatContext *oc,
AVStream *st);
static int tfile (GeglChantO *self);
static void write_video_frame (GeglChantO *self,
AVFormatContext *oc,
AVStream *st);
static void write_audio_frame (GeglChantO *self,
AVFormatContext *oc,
AVStream *st);
g_assert (input);
p->width = result->width;
p->height = result->height;
p->input = input;
if (!inited)
{
tfile (self);
inited = 1;
}
write_video_frame (self, p->oc, p->video_st);
if (p->audio_st)
write_audio_frame (self, p->oc, p->audio_st);
return TRUE;
}
static void class_init (GeglOperationClass *operation_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (operation_class);
gobject_class->finalize = finalize;
GEGL_OPERATION_SINK_CLASS (operation_class)->needs_full = TRUE;
}
#define STREAM_FRAME_RATE 25 /* 25 images/s */
......@@ -491,9 +414,9 @@ open_audio (Priv * p, AVFormatContext * oc, AVStream * st)
}
void
write_audio_frame (GeglChantOperation *op, AVFormatContext * oc, AVStream * st)
write_audio_frame (GeglChantO *op, AVFormatContext * oc, AVStream * st)
{
Priv *p = (Priv*)op->priv;
Priv *p = (Priv*)op->chant_data;
AVCodecContext *c;
AVPacket pkt;
......@@ -542,9 +465,9 @@ close_audio (Priv * p, AVFormatContext * oc, AVStream * st)
/* add a video output stream */
static AVStream *
add_video_stream (GeglChantOperation *op, AVFormatContext * oc, int codec_id)
add_video_stream (GeglChantO *op, AVFormatContext * oc, int codec_id)
{
Priv *p = (Priv*)op->priv;
Priv *p = (Priv*)op->chant_data;
AVCodecContext *c;
AVStream *st;
......@@ -686,10 +609,10 @@ close_video (Priv * p, AVFormatContext * oc, AVStream * st)
/* prepare a dummy image */
static void
fill_yuv_image (GeglChantOperation *op,
AVFrame * pict, int frame_index, int width, int height)
fill_yuv_image (GeglChantO *op,
AVFrame *pict, int frame_index, int width, int height)
{
Priv *p = (Priv*)op->priv;
Priv *p = (Priv*)op->chant_data;
/*memcpy (pict->data[0],
op->input_pad[0]->data,
......@@ -700,10 +623,10 @@ fill_yuv_image (GeglChantOperation *op,
}
static void
write_video_frame (GeglChantOperation *op,
AVFormatContext * oc, AVStream * st)
write_video_frame (GeglChantO *op,
AVFormatContext *oc, AVStream *st)