1/* 2 * Copyright (c) 2006 Paul Richards <paul.richards@gmail.com> 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21/*! 22 * \file libtheoraenc.c 23 * \brief Theora encoder using libtheora. 24 * \author Paul Richards <paul.richards@gmail.com> 25 * 26 * A lot of this is copy / paste from other output codecs in 27 * libavcodec or pure guesswork (or both). 28 * 29 * I have used t_ prefixes on variables which are libtheora types 30 * and o_ prefixes on variables which are libogg types. 31 */ 32 33/* FFmpeg includes */ 34#include "libavutil/intreadwrite.h" 35#include "libavutil/log.h" 36#include "avcodec.h" 37 38/* libtheora includes */ 39#include <theora/theora.h> 40 41typedef struct TheoraContext{ 42 theora_state t_state; 43} TheoraContext; 44 45/*! 46 Concatenates an ogg_packet into the extradata. 47*/ 48static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, const ogg_packet* packet) 49{ 50 char* message = NULL; 51 uint8_t* newdata = NULL; 52 int newsize = avc_context->extradata_size + 2 + packet->bytes; 53 54 if (packet->bytes < 0) { 55 message = "ogg_packet has negative size"; 56 } else if (packet->bytes > 0xffff) { 57 message = "ogg_packet is larger than 65535 bytes"; 58 } else if (newsize < avc_context->extradata_size) { 59 message = "extradata_size would overflow"; 60 } else { 61 newdata = av_realloc(avc_context->extradata, newsize); 62 if (newdata == NULL) { 63 message = "av_realloc failed"; 64 } 65 } 66 if (message != NULL) { 67 av_log(avc_context, AV_LOG_ERROR, "concatenate_packet failed: %s\n", message); 68 return -1; 69 } 70 71 avc_context->extradata = newdata; 72 avc_context->extradata_size = newsize; 73 AV_WB16(avc_context->extradata + (*offset), packet->bytes); 74 *offset += 2; 75 memcpy( avc_context->extradata + (*offset), packet->packet, packet->bytes ); 76 (*offset) += packet->bytes; 77 return 0; 78} 79 80static av_cold int encode_init(AVCodecContext* avc_context) 81{ 82 theora_info t_info; 83 theora_comment t_comment; 84 ogg_packet o_packet; 85 unsigned int offset; 86 TheoraContext *h = avc_context->priv_data; 87 88 /* Set up the theora_info struct */ 89 theora_info_init( &t_info ); 90 t_info.width = avc_context->width; 91 t_info.height = avc_context->height; 92 t_info.frame_width = avc_context->width; 93 t_info.frame_height = avc_context->height; 94 t_info.offset_x = 0; 95 t_info.offset_y = 0; 96 /* Swap numerator and denominator as time_base in AVCodecContext gives the 97 * time period between frames, but theora_info needs the framerate. */ 98 t_info.fps_numerator = avc_context->time_base.den; 99 t_info.fps_denominator = avc_context->time_base.num; 100 if (avc_context->sample_aspect_ratio.num != 0) { 101 t_info.aspect_numerator = avc_context->sample_aspect_ratio.num; 102 t_info.aspect_denominator = avc_context->sample_aspect_ratio.den; 103 } else { 104 t_info.aspect_numerator = 1; 105 t_info.aspect_denominator = 1; 106 } 107 t_info.colorspace = OC_CS_UNSPECIFIED; 108 t_info.pixelformat = OC_PF_420; 109 t_info.target_bitrate = avc_context->bit_rate; 110 t_info.keyframe_frequency = avc_context->gop_size; 111 t_info.keyframe_frequency_force = avc_context->gop_size; 112 t_info.keyframe_mindistance = avc_context->keyint_min; 113 t_info.quality = 0; 114 115 t_info.quick_p = 1; 116 t_info.dropframes_p = 0; 117 t_info.keyframe_auto_p = 1; 118 t_info.keyframe_data_target_bitrate = t_info.target_bitrate * 1.5; 119 t_info.keyframe_auto_threshold = 80; 120 t_info.noise_sensitivity = 1; 121 t_info.sharpness = 0; 122 123 /* Now initialise libtheora */ 124 if (theora_encode_init( &(h->t_state), &t_info ) != 0) { 125 av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n"); 126 return -1; 127 } 128 129 /* Clear up theora_info struct */ 130 theora_info_clear( &t_info ); 131 132 /* 133 Output first header packet consisting of theora 134 header, comment, and tables. 135 136 Each one is prefixed with a 16bit size, then they 137 are concatenated together into ffmpeg's extradata. 138 */ 139 offset = 0; 140 141 /* Header */ 142 theora_encode_header( &(h->t_state), &o_packet ); 143 if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { 144 return -1; 145 } 146 147 /* Comment */ 148 theora_comment_init( &t_comment ); 149 theora_encode_comment( &t_comment, &o_packet ); 150 if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { 151 return -1; 152 } 153 154 /* Tables */ 155 theora_encode_tables( &(h->t_state), &o_packet ); 156 if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { 157 return -1; 158 } 159 160 /* Clear up theora_comment struct */ 161 theora_comment_clear( &t_comment ); 162 163 /* Set up the output AVFrame */ 164 avc_context->coded_frame= avcodec_alloc_frame(); 165 166 return 0; 167} 168 169static int encode_frame( 170 AVCodecContext* avc_context, 171 uint8_t *outbuf, 172 int buf_size, 173 void *data) 174{ 175 yuv_buffer t_yuv_buffer; 176 TheoraContext *h = avc_context->priv_data; 177 AVFrame *frame = data; 178 ogg_packet o_packet; 179 int result; 180 181 assert(avc_context->pix_fmt == PIX_FMT_YUV420P); 182 183 /* Copy planes to the theora yuv_buffer */ 184 if (frame->linesize[1] != frame->linesize[2]) { 185 av_log(avc_context, AV_LOG_ERROR, "U and V stride differ\n"); 186 return -1; 187 } 188 189 t_yuv_buffer.y_width = avc_context->width; 190 t_yuv_buffer.y_height = avc_context->height; 191 t_yuv_buffer.y_stride = frame->linesize[0]; 192 t_yuv_buffer.uv_width = t_yuv_buffer.y_width / 2; 193 t_yuv_buffer.uv_height = t_yuv_buffer.y_height / 2; 194 t_yuv_buffer.uv_stride = frame->linesize[1]; 195 196 t_yuv_buffer.y = frame->data[0]; 197 t_yuv_buffer.u = frame->data[1]; 198 t_yuv_buffer.v = frame->data[2]; 199 200 /* Now call into theora_encode_YUVin */ 201 result = theora_encode_YUVin( &(h->t_state), &t_yuv_buffer ); 202 if (result != 0) { 203 const char* message; 204 switch (result) { 205 case -1: 206 message = "differing frame sizes"; 207 break; 208 case OC_EINVAL: 209 message = "encoder is not ready or is finished"; 210 break; 211 default: 212 message = "unknown reason"; 213 break; 214 } 215 av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result); 216 return -1; 217 } 218 219 /* Pick up returned ogg_packet */ 220 result = theora_encode_packetout( &(h->t_state), 0, &o_packet ); 221 switch (result) { 222 case 0: 223 /* No packet is ready */ 224 return 0; 225 case 1: 226 /* Success, we have a packet */ 227 break; 228 default: 229 av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed [%d]\n", result); 230 return -1; 231 } 232 233 /* Copy ogg_packet content out to buffer */ 234 if (buf_size < o_packet.bytes) { 235 av_log(avc_context, AV_LOG_ERROR, "encoded frame too large\n"); 236 return -1; 237 } 238 memcpy(outbuf, o_packet.packet, o_packet.bytes); 239 240 return o_packet.bytes; 241} 242 243static av_cold int encode_close(AVCodecContext* avc_context) 244{ 245 ogg_packet o_packet; 246 TheoraContext *h = avc_context->priv_data; 247 int result; 248 const char* message; 249 250 result = theora_encode_packetout( &(h->t_state), 1, &o_packet ); 251 theora_clear( &(h->t_state) ); 252 switch (result) { 253 case 0:/* No packet is ready */ 254 case -1:/* Encoding finished */ 255 return 0; 256 case 1: 257 /* We have a packet */ 258 message = "gave us a packet"; 259 break; 260 default: 261 message = "unknown reason"; 262 break; 263 } 264 av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed (%s) [%d]\n", message, result); 265 return -1; 266} 267 268static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; 269 270/*! AVCodec struct exposed to libavcodec */ 271AVCodec libtheora_encoder = 272{ 273 .name = "libtheora", 274 .type = CODEC_TYPE_VIDEO, 275 .id = CODEC_ID_THEORA, 276 .priv_data_size = sizeof(TheoraContext), 277 .init = encode_init, 278 .close = encode_close, 279 .encode = encode_frame, 280 .pix_fmts = supported_pixel_formats, 281 .long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"), 282}; 283