Mercurial > libavcodec.hg
changeset 6738:bdacae101076 libavcodec
Add Dirac support through libschroedinger.
patch by Anuradha Suraparaju, anuradha rd.bbc.co uk
author | diego |
---|---|
date | Sat, 03 May 2008 13:59:45 +0000 |
parents | dcb3b40c7b71 |
children | 4db65caccc9b |
files | Makefile allcodecs.c libschroedinger.c libschroedinger.h libschroedingerdec.c libschroedingerenc.c |
diffstat | 6 files changed, 841 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Sat May 03 13:55:31 2008 +0000 +++ b/Makefile Sat May 03 13:59:45 2008 +0000 @@ -325,6 +325,8 @@ OBJS-$(CONFIG_LIBFAAD) += libfaad.o OBJS-$(CONFIG_LIBGSM) += libgsm.o OBJS-$(CONFIG_LIBMP3LAME) += libmp3lame.o +OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER) += libschroedingerdec.o libschroedinger.o libdirac_libschro.o +OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o libschroedinger.o libdirac_libschro.o OBJS-$(CONFIG_LIBTHEORA) += libtheoraenc.o OBJS-$(CONFIG_LIBVORBIS) += libvorbis.o OBJS-$(CONFIG_LIBX264) += libx264.o
--- a/allcodecs.c Sat May 03 13:55:31 2008 +0000 +++ b/allcodecs.c Sat May 03 13:59:45 2008 +0000 @@ -283,6 +283,7 @@ REGISTER_ENCDEC (LIBGSM, libgsm); REGISTER_ENCDEC (LIBGSM_MS, libgsm_ms); REGISTER_ENCODER (LIBMP3LAME, libmp3lame); + REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger); REGISTER_ENCODER (LIBTHEORA, libtheora); REGISTER_ENCODER (LIBVORBIS, libvorbis); REGISTER_ENCODER (LIBX264, libx264);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libschroedinger.c Sat May 03 13:59:45 2008 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com > + * + * This file is part of FFmpeg. + * + * FFmpeg 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 + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedinger.c +* function definitions common to libschroedingerdec.c and libschroedingerenc.c +*/ + +#include "libdirac_libschro.h" +#include "libschroedinger.h" + +/** +* Schroedinger video preset table. Ensure that this tables matches up correctly +* with the ff_dirac_schro_video_format_info table in libdirac_libschro.c. +*/ +static const SchroVideoFormatEnum ff_schro_video_formats[]={ + SCHRO_VIDEO_FORMAT_CUSTOM , + SCHRO_VIDEO_FORMAT_QSIF , + SCHRO_VIDEO_FORMAT_QCIF , + SCHRO_VIDEO_FORMAT_SIF , + SCHRO_VIDEO_FORMAT_CIF , + SCHRO_VIDEO_FORMAT_4SIF , + SCHRO_VIDEO_FORMAT_4CIF , + SCHRO_VIDEO_FORMAT_SD480I_60 , + SCHRO_VIDEO_FORMAT_SD576I_50 , + SCHRO_VIDEO_FORMAT_HD720P_60 , + SCHRO_VIDEO_FORMAT_HD720P_50 , + SCHRO_VIDEO_FORMAT_HD1080I_60 , + SCHRO_VIDEO_FORMAT_HD1080I_50 , + SCHRO_VIDEO_FORMAT_HD1080P_60 , + SCHRO_VIDEO_FORMAT_HD1080P_50 , + SCHRO_VIDEO_FORMAT_DC2K_24 , + SCHRO_VIDEO_FORMAT_DC4K_24 , +}; + +SchroVideoFormatEnum ff_get_schro_video_format_preset(AVCodecContext *avccontext) +{ + unsigned int num_formats = sizeof(ff_schro_video_formats) / + sizeof(ff_schro_video_formats[0]); + + unsigned int idx = ff_dirac_schro_get_video_format_idx (avccontext); + + return (idx < num_formats) ? + ff_schro_video_formats[idx] : SCHRO_VIDEO_FORMAT_CUSTOM; +} + +int ff_get_schro_frame_format (SchroChromaFormat schro_pix_fmt, + SchroFrameFormat *schro_frame_fmt) +{ + unsigned int num_formats = sizeof(ffmpeg_schro_pixel_format_map) / + sizeof(ffmpeg_schro_pixel_format_map[0]); + + int idx; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt == schro_pix_fmt) { + *schro_frame_fmt = + ffmpeg_schro_pixel_format_map[idx].schro_frame_fmt; + return 0; + } + } + return -1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libschroedinger.h Sat May 03 13:59:45 2008 +0000 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com > + * + * This file is part of FFmpeg. + * + * FFmpeg 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 + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedinger.h +* data structures common to libschroedingerdec.c and libschroedingerenc.c +*/ + +#ifndef FFMPEG_LIBSCHROEDINGER_H +#define FFMPEG_LIBSCHROEDINGER_H + +#include "config.h" + +#ifdef CONFIG_LIBSCHROEDINGER + +#include <schroedinger/schrobitstream.h> +#include <schroedinger/schroframe.h> +#include "avcodec.h" + +static const struct { + enum PixelFormat ff_pix_fmt; + SchroChromaFormat schro_pix_fmt; + SchroFrameFormat schro_frame_fmt; +} ffmpeg_schro_pixel_format_map[] = { + { PIX_FMT_YUV420P, SCHRO_CHROMA_420, SCHRO_FRAME_FORMAT_U8_420 }, + { PIX_FMT_YUV422P, SCHRO_CHROMA_422, SCHRO_FRAME_FORMAT_U8_422 }, + { PIX_FMT_YUV444P, SCHRO_CHROMA_444, SCHRO_FRAME_FORMAT_U8_444 }, +}; + +/** +* Returns the video format preset matching the input video dimensions and +* time base. +*/ +SchroVideoFormatEnum ff_get_schro_video_format_preset (AVCodecContext *avccontext); + +/** +* Sets the Schroedinger frame format corresponding to the Schro chroma format +* passed. Returns 0 on success, -1 on failure. +*/ +int ff_get_schro_frame_format (SchroChromaFormat schro_chroma_fmt, + SchroFrameFormat *schro_frame_fmt); + +#endif /* CONFIG_LIBSCHROEDINGER */ +#endif /* FFMPEG_LIBSCHROEDINGER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libschroedingerdec.c Sat May 03 13:59:45 2008 +0000 @@ -0,0 +1,310 @@ +/* + * Dirac decoder support via Schroedinger libraries + * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com > + * + * This file is part of FFmpeg. + * + * FFmpeg 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 + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedingerdec.c +* Dirac decoder support via libschroedinger-1.0 libraries. More details about +* the Schroedinger project can be found at http://www.diracvideo.org/. +* The library implements Dirac Specification Version 2.2. +* (http://dirac.sourceforge.net/specification.html). +*/ + +#include "avcodec.h" +#include "libdirac_libschro.h" +#include "libschroedinger.h" + +#undef NDEBUG +#include <assert.h> + + +#include <schroedinger/schro.h> +#include <schroedinger/schrodebug.h> +#include <schroedinger/schrovideoformat.h> + +/** libschroedinger decoder private data */ +typedef struct FfmpegSchroDecoderParams +{ + /** Schroedinger video format */ + SchroVideoFormat *format; + + /** Schroedinger frame format */ + SchroFrameFormat frame_format; + + /** decoder handle */ + SchroDecoder* decoder; + + /** queue storing decoded frames */ + FfmpegDiracSchroQueue dec_frame_queue; + + /** end of sequence signalled */ + int eos_signalled; + + /** end of sequence pulled */ + int eos_pulled; + + /** decoded picture */ + AVPicture dec_pic; +} FfmpegSchroDecoderParams; + +/** +* Returns FFmpeg chroma format. +*/ +static enum PixelFormat GetFfmpegChromaFormat(SchroChromaFormat schro_pix_fmt) +{ + int num_formats = sizeof(ffmpeg_schro_pixel_format_map) / + sizeof(ffmpeg_schro_pixel_format_map[0]); + int idx; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt == schro_pix_fmt) { + return ffmpeg_schro_pixel_format_map[idx].ff_pix_fmt; + } + } + return PIX_FMT_NONE; +} + +/*-------------------------DECODER------------------------------------------*/ + +static int libschroedinger_decode_init(AVCodecContext *avccontext) +{ + + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data ; + /* First of all, initialize our supporting libraries. */ + schro_init(); + + schro_debug_set_level(avccontext->debug); + p_schro_params->decoder = schro_decoder_new(); + schro_decoder_set_skip_ratio(p_schro_params->decoder, 1); + + if (!p_schro_params->decoder) + return -1; + + /* Initialize the decoded frame queue. */ + ff_dirac_schro_queue_init (&p_schro_params->dec_frame_queue); + return 0 ; +} + +static void libschroedinger_decode_buffer_free (SchroBuffer *schro_buf, + void *priv) +{ + av_freep(&priv); +} + +static void libschroedinger_decode_frame_free (void *frame) +{ + schro_frame_unref(frame); +} + +static void libschroedinger_handle_first_access_unit(AVCodecContext *avccontext) +{ + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + SchroDecoder *decoder = p_schro_params->decoder; + + p_schro_params->format = schro_decoder_get_video_format (decoder); + + /* Tell FFmpeg about sequence details. */ + if(avcodec_check_dimensions(avccontext, p_schro_params->format->width, + p_schro_params->format->height) < 0) { + av_log(avccontext, AV_LOG_ERROR, "invalid dimensions (%dx%d)\n", + p_schro_params->format->width, p_schro_params->format->height); + avccontext->height = avccontext->width = 0; + return -1; + } + avccontext->height = p_schro_params->format->height; + avccontext->width = p_schro_params->format->width; + avccontext->pix_fmt = + GetFfmpegChromaFormat(p_schro_params->format->chroma_format); + + if (ff_get_schro_frame_format( p_schro_params->format->chroma_format, + &p_schro_params->frame_format) == -1) { + av_log (avccontext, AV_LOG_ERROR, + "This codec currently only supports planar YUV 4:2:0, 4:2:2 " + "and 4:4:4 formats.\n"); + return -1; + } + + avccontext->time_base.den = p_schro_params->format->frame_rate_numerator; + avccontext->time_base.num = p_schro_params->format->frame_rate_denominator; + + if (p_schro_params->dec_pic.data[0] == NULL) + { + avpicture_alloc(&p_schro_params->dec_pic, + avccontext->pix_fmt, + avccontext->width, + avccontext->height); + } +} + +static int libschroedinger_decode_frame(AVCodecContext *avccontext, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + SchroDecoder *decoder = p_schro_params->decoder; + SchroVideoFormat *format; + AVPicture *picture = data; + SchroBuffer *enc_buf; + SchroFrame* frame; + int state; + int go = 1; + + *data_size = 0; + + if (buf_size>0) { + unsigned char *in_buf = av_malloc(buf_size); + memcpy (in_buf, buf, buf_size); + enc_buf = schro_buffer_new_with_data (in_buf, buf_size); + enc_buf->free = libschroedinger_decode_buffer_free; + enc_buf->priv = in_buf; + /* Push buffer into decoder. */ + state = schro_decoder_push (decoder, enc_buf); + if (state == SCHRO_DECODER_FIRST_ACCESS_UNIT) + libschroedinger_handle_first_access_unit(avccontext); + } else { + if (!p_schro_params->eos_signalled) { + state = schro_decoder_push_end_of_stream(decoder); + p_schro_params->eos_signalled = 1; + } + } + + format = p_schro_params->format; + + while (go) { + /* Parse data and process result. */ + state = schro_decoder_wait (decoder); + switch (state) + { + case SCHRO_DECODER_FIRST_ACCESS_UNIT: + libschroedinger_handle_first_access_unit (avccontext); + break; + + case SCHRO_DECODER_NEED_BITS: + /* Need more input data - stop iterating over what we have. */ + go = 0; + break; + + case SCHRO_DECODER_NEED_FRAME: + /* Decoder needs a frame - create one and push it in. */ + + frame = schro_frame_new_and_alloc(NULL, + p_schro_params->frame_format, + format->width, + format->height); + schro_decoder_add_output_picture (decoder, frame); + break; + + case SCHRO_DECODER_OK: + /* Pull a frame out of the decoder. */ + frame = schro_decoder_pull (decoder); + + if (frame) { + ff_dirac_schro_queue_push_back( + &p_schro_params->dec_frame_queue, + frame); + } + break; + case SCHRO_DECODER_EOS: + go = 0; + p_schro_params->eos_pulled = 1; + schro_decoder_reset (decoder); + break; + + case SCHRO_DECODER_ERROR: + return -1; + break; + } + } + + /* Grab next frame to be returned from the top of the queue. */ + frame = ff_dirac_schro_queue_pop(&p_schro_params->dec_frame_queue); + + if (frame != NULL) { + memcpy (p_schro_params->dec_pic.data[0], + frame->components[0].data, + frame->components[0].length); + + memcpy (p_schro_params->dec_pic.data[1], + frame->components[1].data, + frame->components[1].length); + + memcpy (p_schro_params->dec_pic.data[2], + frame->components[2].data, + frame->components[2].length); + + /* Fill picture with current buffer data from Schroedinger. */ + avpicture_fill(picture, p_schro_params->dec_pic.data[0], + avccontext->pix_fmt, + avccontext->width, avccontext->height); + + *data_size = sizeof(AVPicture); + + /* Now free the frame resources. */ + libschroedinger_decode_frame_free (frame); + } + return buf_size; +} + + +static int libschroedinger_decode_close(AVCodecContext *avccontext) +{ + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + /* Free the decoder. */ + schro_decoder_free (p_schro_params->decoder); + av_freep(&p_schro_params->format); + + avpicture_free (&p_schro_params->dec_pic); + + /* Free data in the output frame queue. */ + ff_dirac_schro_queue_free (&p_schro_params->dec_frame_queue, + libschroedinger_decode_frame_free); + + return 0 ; +} + +static void libschroedinger_flush (AVCodecContext *avccontext) +{ + /* Got a seek request. Free the decoded frames queue and then reset + * the decoder */ + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + + /* Free data in the output frame queue. */ + ff_dirac_schro_queue_free (&p_schro_params->dec_frame_queue, + libschroedinger_decode_frame_free); + + ff_dirac_schro_queue_init (&p_schro_params->dec_frame_queue); + schro_decoder_reset(p_schro_params->decoder); + p_schro_params->eos_pulled = 0; + p_schro_params->eos_signalled = 0; +} + +AVCodec libschroedinger_decoder = { + "libschroedinger", + CODEC_TYPE_VIDEO, + CODEC_ID_DIRAC, + sizeof(FfmpegSchroDecoderParams), + libschroedinger_decode_init, + NULL, + libschroedinger_decode_close, + libschroedinger_decode_frame, + CODEC_CAP_DELAY, + .flush = libschroedinger_flush +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libschroedingerenc.c Sat May 03 13:59:45 2008 +0000 @@ -0,0 +1,387 @@ +/* + * Dirac encoder support via Schroedinger libraries + * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com > + * + * This file is part of FFmpeg. + * + * FFmpeg 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 + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedingerenc.c +* Dirac encoder support via libschroedinger-1.0 libraries. More details about +* the Schroedinger project can be found at http://www.diracvideo.org/. +* The library implements Dirac Specification Version 2.2 +* (http://dirac.sourceforge.net/specification.html). +*/ + +#undef NDEBUG +#include <assert.h> + +#include <schroedinger/schro.h> +#include <schroedinger/schrodebug.h> +#include <schroedinger/schrovideoformat.h> + +#include "avcodec.h" +#include "libdirac_libschro.h" +#include "libschroedinger.h" + + +/** libschroedinger encoder private data */ +typedef struct FfmpegSchroEncoderParams +{ + /** Schroedinger video format */ + SchroVideoFormat *format; + + /** Schroedinger frame format */ + SchroFrameFormat frame_format; + + /** frame being encoded */ + AVFrame picture; + + /** frame size */ + int frame_size; + + /** Schroedinger encoder handle*/ + SchroEncoder* encoder; + + /** queue storing encoded frames */ + FfmpegDiracSchroQueue enc_frame_queue; + + /** end of sequence signalled */ + int eos_signalled; + + /** end of sequence pulled */ + int eos_pulled; +} FfmpegSchroEncoderParams; + +/** +* Works out Schro-compatible chroma format. +*/ +static int SetSchroChromaFormat(AVCodecContext *avccontext) +{ + int num_formats = sizeof(ffmpeg_schro_pixel_format_map) / + sizeof(ffmpeg_schro_pixel_format_map[0]); + int idx; + + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_schro_pixel_format_map[idx].ff_pix_fmt == + avccontext->pix_fmt) { + p_schro_params->format->chroma_format = + ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt; + return 0; + } + } + + av_log (avccontext, AV_LOG_ERROR, + "This codec currently only supports planar YUV 4:2:0, 4:2:2" + " and 4:4:4 formats.\n"); + + return -1; +} + +static int libschroedinger_encode_init(AVCodecContext *avccontext) +{ + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + SchroVideoFormatEnum preset; + + /* Initialize the libraries that libschroedinger depends on. */ + schro_init(); + + /* Create an encoder object. */ + p_schro_params->encoder = schro_encoder_new(); + + if (!p_schro_params->encoder) { + av_log(avccontext, AV_LOG_ERROR, + "Unrecoverable Error: schro_encoder_new failed. "); + return -1; + } + + /* Initialize the format. */ + preset = ff_get_schro_video_format_preset(avccontext); + p_schro_params->format = + schro_encoder_get_video_format(p_schro_params->encoder); + schro_video_format_set_std_video_format (p_schro_params->format, preset); + p_schro_params->format->width = avccontext->width; + p_schro_params->format->height = avccontext->height; + + if (SetSchroChromaFormat(avccontext) == -1) + return -1; + + if (ff_get_schro_frame_format(p_schro_params->format->chroma_format, + &p_schro_params->frame_format) == -1) { + av_log (avccontext, AV_LOG_ERROR, + "This codec currently supports only planar YUV 4:2:0, 4:2:2" + " and 4:4:4 formats.\n"); + return -1; + } + + p_schro_params->format->frame_rate_numerator = avccontext->time_base.den; + p_schro_params->format->frame_rate_denominator = avccontext->time_base.num; + + p_schro_params->frame_size = avpicture_get_size(avccontext->pix_fmt, + avccontext->width, + avccontext->height); + + avccontext->coded_frame = &p_schro_params->picture; + + if (avccontext->gop_size == 0){ + schro_encoder_setting_set_double (p_schro_params->encoder, + "gop_structure", + SCHRO_ENCODER_GOP_INTRA_ONLY); + } + else { + schro_encoder_setting_set_double (p_schro_params->encoder, + "gop_structure", + SCHRO_ENCODER_GOP_BIREF); + avccontext->has_b_frames = 1; + } + + /* FIXME - Need to handle SCHRO_ENCODER_RATE_CONTROL_LOW_DELAY. */ + if (avccontext->flags & CODEC_FLAG_QSCALE) { + if (avccontext->global_quality == 0) { + /* lossless coding */ + schro_encoder_setting_set_double (p_schro_params->encoder, + "rate_control", + SCHRO_ENCODER_RATE_CONTROL_LOSSLESS); + } else { + int noise_threshold; + schro_encoder_setting_set_double (p_schro_params->encoder, + "rate_control", + SCHRO_ENCODER_RATE_CONTROL_CONSTANT_NOISE_THRESHOLD); + + noise_threshold = avccontext->global_quality/FF_QP2LAMBDA; + if (noise_threshold > 100) + noise_threshold = 100; + schro_encoder_setting_set_double (p_schro_params->encoder, + "noise_threshold", + noise_threshold); + } + } + else { + schro_encoder_setting_set_double ( p_schro_params->encoder, + "rate_control", + SCHRO_ENCODER_RATE_CONTROL_CONSTANT_BITRATE); + + schro_encoder_setting_set_double (p_schro_params->encoder, + "bitrate", + avccontext->bit_rate); + + } + + if (avccontext->flags & CODEC_FLAG_INTERLACED_ME) { + /* All material can be coded as interlaced or progressive + irrespective of the type of source material. */ + schro_encoder_setting_set_double (p_schro_params->encoder, + "interlaced_coding", 1); + } + + /* FIXME: Signal range hardcoded to 8-bit data until both libschroedinger + * and libdirac support other bit-depth data. */ + schro_video_format_set_std_signal_range(p_schro_params->format, + SCHRO_SIGNAL_RANGE_8BIT_VIDEO); + + + /* Hardcode motion vector precision to quarter pixel. */ + schro_encoder_setting_set_double (p_schro_params->encoder, + "mv_precision", 2); + + /* Set the encoder format. */ + schro_encoder_set_video_format(p_schro_params->encoder, + p_schro_params->format); + + /* Set the debug level. */ + schro_debug_set_level (avccontext->debug); + + schro_encoder_start (p_schro_params->encoder); + + /* Initialize the encoded frame queue. */ + ff_dirac_schro_queue_init (&p_schro_params->enc_frame_queue); + return 0 ; +} + +static SchroFrame *libschroedinger_frame_from_data (AVCodecContext *avccontext, + void *in_data) +{ + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + SchroFrame *in_frame; + /* Input line size may differ from what the codec supports. Especially + * when transcoding from one format to another. So use avpicture_layout + * to copy the frame. */ + in_frame = schro_frame_new_and_alloc (NULL, + p_schro_params->frame_format, + p_schro_params->format->width, + p_schro_params->format->height); + + avpicture_layout ((AVPicture *)in_data, avccontext->pix_fmt, + avccontext->width, avccontext->height, + in_frame->components[0].data, + p_schro_params->frame_size); + + return in_frame; +} + +static void SchroedingerFreeFrame(void *data) +{ + FfmpegDiracSchroEncodedFrame *enc_frame = data; + + av_freep (&(enc_frame->p_encbuf)); + av_free(enc_frame); +} + +static int libschroedinger_encode_frame(AVCodecContext *avccontext, + unsigned char *frame, + int buf_size, void *data) +{ + int enc_size = 0; + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + SchroEncoder *encoder = p_schro_params->encoder; + struct FfmpegDiracSchroEncodedFrame* p_frame_output = NULL; + int go = 1; + SchroBuffer *enc_buf; + int presentation_frame; + int parse_code; + + if(data == NULL) { + /* Push end of sequence if not already signalled. */ + if (!p_schro_params->eos_signalled) { + schro_encoder_end_of_stream(encoder); + p_schro_params->eos_signalled = 1; + } + } else { + /* Allocate frame data to schro input buffer. */ + SchroFrame *in_frame = libschroedinger_frame_from_data (avccontext, + data); + /* Load next frame. */ + schro_encoder_push_frame(encoder, in_frame); + } + + if (p_schro_params->eos_pulled) + go = 0; + + /* Now check to see if we have any output from the encoder. */ + while (go) { + SchroStateEnum state; + state = schro_encoder_wait(encoder); + switch (state) + { + case SCHRO_STATE_HAVE_BUFFER: + case SCHRO_STATE_END_OF_STREAM: + enc_buf = schro_encoder_pull (encoder, + &presentation_frame); + assert (enc_buf->length > 0); + assert (enc_buf->length <= buf_size); + + /* Create output frame. */ + p_frame_output = av_mallocz(sizeof(FfmpegDiracSchroEncodedFrame)); + /* Set output data. */ + p_frame_output->size = enc_buf->length; + p_frame_output->p_encbuf = av_malloc(enc_buf->length); + memcpy(p_frame_output->p_encbuf, enc_buf->data, enc_buf->length); + + parse_code = enc_buf->data[4]; + if (SCHRO_PARSE_CODE_IS_INTRA(parse_code) && + SCHRO_PARSE_CODE_IS_REFERENCE(parse_code)) { + p_frame_output->key_frame = 1; + } + + /* Parse the coded frame number from the bitstream. Bytes 14 + * through 17 represesent the frame number. */ + if (SCHRO_PARSE_CODE_IS_PICTURE(parse_code)) + { + assert (enc_buf->length >= 17); + p_frame_output->frame_num = (enc_buf->data[13] << 24) + + (enc_buf->data[14] << 16) + + (enc_buf->data[15] << 8) + + enc_buf->data[16]; + } + + ff_dirac_schro_queue_push_back (&p_schro_params->enc_frame_queue, + p_frame_output); + schro_buffer_unref (enc_buf); + + if (state == SCHRO_STATE_END_OF_STREAM) { + p_schro_params->eos_pulled = 1; + go = 0; + } + break; + + case SCHRO_STATE_NEED_FRAME: + go = 0; + break; + + case SCHRO_STATE_AGAIN: + break; + + default: + av_log(avccontext, AV_LOG_ERROR, "Unknown Schro Encoder state\n"); + return -1; + } + } + + /* Copy 'next' frame in queue. */ + p_frame_output = + ff_dirac_schro_queue_pop (&p_schro_params->enc_frame_queue); + + if (p_frame_output == NULL) + return 0; + + memcpy(frame, p_frame_output->p_encbuf, p_frame_output->size); + avccontext->coded_frame->key_frame = p_frame_output->key_frame; + /* Use the frame number of the encoded frame as the pts. It is OK to + * do so since Dirac is a constant frame rate codec. It expects input + * to be of constant frame rate. */ + avccontext->coded_frame->pts = p_frame_output->frame_num; + enc_size = p_frame_output->size; + + /* free frame */ + SchroedingerFreeFrame (p_frame_output); + + return enc_size; +} + + +static int libschroedinger_encode_close(AVCodecContext *avccontext) +{ + + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + + /* Close the encoder. */ + schro_encoder_free(p_schro_params->encoder); + + /* Free data in the output frame queue. */ + ff_dirac_schro_queue_free (&p_schro_params->enc_frame_queue, + SchroedingerFreeFrame); + + /* Free the video format structure. */ + av_freep(&p_schro_params->format); + + return 0 ; +} + + +AVCodec libschroedinger_encoder = { + "libschroedinger", + CODEC_TYPE_VIDEO, + CODEC_ID_DIRAC, + sizeof(FfmpegSchroEncoderParams), + libschroedinger_encode_init, + libschroedinger_encode_frame, + libschroedinger_encode_close, + .capabilities= CODEC_CAP_DELAY, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, -1}, +};