patch by Anuradha Suraparaju, anuradha rd.bbc.co uk Originally committed as revision 13046 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -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); | |||
| @@ -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; | |||
| } | |||
| @@ -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 */ | |||
| @@ -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 | |||
| }; | |||
| @@ -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}, | |||
| }; | |||