Commit f7cd9eed authored by Anuradha Suraparaju's avatar Anuradha Suraparaju Committed by Diego Biurrun

Add Dirac support through libschroedinger.

patch by Anuradha Suraparaju, anuradha rd.bbc.co uk

Originally committed as revision 13046 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 34499963
......@@ -98,6 +98,7 @@ show_help(){
echo " --enable-libmp3lame enable MP3 encoding via libmp3lame [default=no]"
echo " --enable-libnut enable NUT (de)muxing via libnut,"
echo " native demuxer exists [default=no]"
echo " --enable-libschroedinger enable Dirac support via libschroedinger [default=no]"
echo " --enable-libtheora enable Theora encoding via libtheora [default=no]"
echo " --enable-libvorbis enable Vorbis encoding via libvorbis,"
echo " native implementation exists [default=no]"
......@@ -649,6 +650,7 @@ CONFIG_LIST="
libgsm
libmp3lame
libnut
libschroedinger
libtheora
libvorbis
libx264
......@@ -834,6 +836,8 @@ libgsm_encoder_deps="libgsm"
libgsm_ms_decoder_deps="libgsm"
libgsm_ms_encoder_deps="libgsm"
libmp3lame_encoder_deps="libmp3lame"
libschroedinger_decoder_deps="libschroedinger"
libschroedinger_encoder_deps="libschroedinger"
libtheora_encoder_deps="libtheora"
libvorbis_encoder_deps="libvorbis"
libx264_encoder_deps="libx264"
......@@ -1637,6 +1641,8 @@ enabled libfaad && require2 libfaad faad.h faacDecOpen -lfaad
enabled libgsm && require libgsm gsm.h gsm_create -lgsm
enabled libmp3lame && require LAME lame/lame.h lame_init -lmp3lame -lm
enabled libnut && require libnut libnut.h nut_demuxer_init -lnut
enabled libschroedinger && add_cflags $(pkg-config --cflags schroedinger-1.0) \
&& require libschroedinger schroedinger/schro.h schro_init -lschroedinger-1.0 -lpthread -loil-0.3 -lm -lrt
enabled libtheora && require libtheora theora/theora.h theora_info_init -ltheora -logg
enabled libvorbis && require libvorbis vorbis/vorbisenc.h vorbis_info_init -lvorbisenc -lvorbis -logg
enabled libx264 && require x264 x264.h x264_encoder_open -lx264 -lm
......@@ -1923,6 +1929,7 @@ echo "libfaad dlopened ${libfaadbin-no}"
echo "libgsm enabled ${libgsm-no}"
echo "libmp3lame enabled ${libmp3lame-no}"
echo "libnut enabled ${libnut-no}"
echo "libschroedinger enabled ${libschroedinger-no}"
echo "libtheora enabled ${libtheora-no}"
echo "libvorbis enabled ${libvorbis-no}"
echo "x264 enabled ${libx264-no}"
......
......@@ -325,6 +325,8 @@ OBJS-$(CONFIG_LIBFAAC) += libfaac.o
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
......
......@@ -283,6 +283,7 @@ void avcodec_register_all(void)
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);
......
/*
* 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;
}
/*
* 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 */
/*
* 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
};
/*
* 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},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment