Mercurial > libavcodec.hg
annotate libtheoraenc.c @ 8204:507854688c43 libavcodec
Some BMP files have file size declared in the header equal to headers size
without image data, so try to correct that value before conducting checks on
declared file size.
author | kostya |
---|---|
date | Mon, 24 Nov 2008 11:24:02 +0000 |
parents | e943e1409077 |
children | d679fd3a5359 |
rev | line source |
---|---|
4403 | 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 | |
5215 | 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
4403 | 19 */ |
20 | |
21 /*! | |
22 * \file theoraenc.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 */ | |
6763 | 34 #include "libavutil/log.h" |
4403 | 35 #include "avcodec.h" |
36 | |
37 /* libtheora includes */ | |
38 #include <theora/theora.h> | |
39 | |
40 typedef struct TheoraContext{ | |
41 theora_state t_state; | |
42 } TheoraContext; | |
43 | |
44 /*! | |
45 Concatenates an ogg_packet into the extradata. | |
46 */ | |
47 static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, const ogg_packet* packet) | |
48 { | |
49 char* message = NULL; | |
50 uint8_t* newdata = NULL; | |
51 int newsize = avc_context->extradata_size + 2 + packet->bytes; | |
52 | |
53 if (packet->bytes < 0) { | |
54 message = "ogg_packet has negative size"; | |
55 } else if (packet->bytes > 0xffff) { | |
56 message = "ogg_packet is larger than 65535 bytes"; | |
57 } else if (newsize < avc_context->extradata_size) { | |
58 message = "extradata_size would overflow"; | |
59 } else { | |
60 newdata = av_realloc(avc_context->extradata, newsize); | |
61 if (newdata == NULL) { | |
62 message = "av_realloc failed"; | |
63 } | |
64 } | |
65 if (message != NULL) { | |
66 av_log(avc_context, AV_LOG_ERROR, "concatenate_packet failed: %s\n", message); | |
67 return -1; | |
68 } | |
69 | |
70 avc_context->extradata = newdata; | |
71 avc_context->extradata_size = newsize; | |
5089 | 72 AV_WB16(avc_context->extradata + (*offset), packet->bytes); |
73 *offset += 2; | |
4403 | 74 memcpy( avc_context->extradata + (*offset), packet->packet, packet->bytes ); |
75 (*offset) += packet->bytes; | |
76 return 0; | |
77 } | |
78 | |
79 static int encode_init(AVCodecContext* avc_context) | |
80 { | |
81 theora_info t_info; | |
82 theora_comment t_comment; | |
83 ogg_packet o_packet; | |
84 unsigned int offset; | |
85 TheoraContext *h = avc_context->priv_data; | |
86 | |
87 /* Set up the theora_info struct */ | |
88 theora_info_init( &t_info ); | |
89 t_info.width = avc_context->width; | |
90 t_info.height = avc_context->height; | |
91 t_info.frame_width = avc_context->width; | |
92 t_info.frame_height = avc_context->height; | |
93 t_info.offset_x = 0; | |
94 t_info.offset_y = 0; | |
4496
a02a0d06e99b
Add a comment about swapped numerator and denominator.
diego
parents:
4403
diff
changeset
|
95 /* Swap numerator and denominator as time_base in AVCodecContext gives the |
a02a0d06e99b
Add a comment about swapped numerator and denominator.
diego
parents:
4403
diff
changeset
|
96 * time period between frames, but theora_info needs the framerate. */ |
4403 | 97 t_info.fps_numerator = avc_context->time_base.den; |
98 t_info.fps_denominator = avc_context->time_base.num; | |
99 if (avc_context->sample_aspect_ratio.num != 0) { | |
100 t_info.aspect_numerator = avc_context->sample_aspect_ratio.num; | |
101 t_info.aspect_denominator = avc_context->sample_aspect_ratio.den; | |
102 } else { | |
103 t_info.aspect_numerator = 1; | |
104 t_info.aspect_denominator = 1; | |
105 } | |
106 t_info.colorspace = OC_CS_UNSPECIFIED; | |
107 t_info.pixelformat = OC_PF_420; | |
108 t_info.target_bitrate = avc_context->bit_rate; | |
109 t_info.keyframe_frequency = avc_context->gop_size; | |
110 t_info.keyframe_frequency_force = avc_context->gop_size; | |
111 t_info.keyframe_mindistance = avc_context->keyint_min; | |
112 t_info.quality = 0; | |
113 | |
114 t_info.quick_p = 1; | |
115 t_info.dropframes_p = 0; | |
116 t_info.keyframe_auto_p = 1; | |
117 t_info.keyframe_data_target_bitrate = t_info.target_bitrate * 1.5; | |
118 t_info.keyframe_auto_threshold = 80; | |
119 t_info.noise_sensitivity = 1; | |
120 t_info.sharpness = 0; | |
121 | |
122 /* Now initialise libtheora */ | |
123 if (theora_encode_init( &(h->t_state), &t_info ) != 0) { | |
124 av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n"); | |
125 return -1; | |
126 } | |
127 | |
128 /* Clear up theora_info struct */ | |
129 theora_info_clear( &t_info ); | |
130 | |
131 /* | |
132 Output first header packet consisting of theora | |
133 header, comment, and tables. | |
134 | |
135 Each one is prefixed with a 16bit size, then they | |
136 are concatenated together into ffmpeg's extradata. | |
137 */ | |
138 offset = 0; | |
139 | |
140 /* Header */ | |
141 theora_encode_header( &(h->t_state), &o_packet ); | |
142 if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { | |
143 return -1; | |
144 } | |
145 | |
146 /* Comment */ | |
147 theora_comment_init( &t_comment ); | |
148 theora_encode_comment( &t_comment, &o_packet ); | |
149 if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { | |
150 return -1; | |
151 } | |
152 | |
153 /* Tables */ | |
154 theora_encode_tables( &(h->t_state), &o_packet ); | |
155 if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { | |
156 return -1; | |
157 } | |
158 | |
159 /* Clear up theora_comment struct */ | |
160 theora_comment_clear( &t_comment ); | |
161 | |
162 /* Set up the output AVFrame */ | |
163 avc_context->coded_frame= avcodec_alloc_frame(); | |
164 | |
165 return 0; | |
166 } | |
167 | |
168 static int encode_frame( | |
169 AVCodecContext* avc_context, | |
170 uint8_t *outbuf, | |
171 int buf_size, | |
172 void *data) | |
173 { | |
174 yuv_buffer t_yuv_buffer; | |
175 TheoraContext *h = avc_context->priv_data; | |
176 AVFrame *frame = data; | |
177 ogg_packet o_packet; | |
178 int result; | |
179 | |
180 assert(avc_context->pix_fmt == PIX_FMT_YUV420P); | |
181 | |
182 /* Copy planes to the theora yuv_buffer */ | |
183 if (frame->linesize[1] != frame->linesize[2]) { | |
184 av_log(avc_context, AV_LOG_ERROR, "U and V stride differ\n"); | |
185 return -1; | |
186 } | |
187 | |
188 t_yuv_buffer.y_width = avc_context->width; | |
189 t_yuv_buffer.y_height = avc_context->height; | |
190 t_yuv_buffer.y_stride = frame->linesize[0]; | |
191 t_yuv_buffer.uv_width = t_yuv_buffer.y_width / 2; | |
192 t_yuv_buffer.uv_height = t_yuv_buffer.y_height / 2; | |
193 t_yuv_buffer.uv_stride = frame->linesize[1]; | |
194 | |
195 t_yuv_buffer.y = frame->data[0]; | |
196 t_yuv_buffer.u = frame->data[1]; | |
197 t_yuv_buffer.v = frame->data[2]; | |
198 | |
199 /* Now call into theora_encode_YUVin */ | |
200 result = theora_encode_YUVin( &(h->t_state), &t_yuv_buffer ); | |
201 if (result != 0) { | |
202 const char* message; | |
203 switch (result) { | |
204 case -1: | |
205 message = "differing frame sizes"; | |
206 break; | |
207 case OC_EINVAL: | |
208 message = "encoder is not ready or is finished"; | |
209 break; | |
210 default: | |
211 message = "unknown reason"; | |
212 break; | |
213 } | |
214 av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result); | |
215 return -1; | |
216 } | |
217 | |
218 /* Pick up returned ogg_packet */ | |
219 result = theora_encode_packetout( &(h->t_state), 0, &o_packet ); | |
220 switch (result) { | |
221 case 0: | |
222 /* No packet is ready */ | |
223 return 0; | |
224 case 1: | |
225 /* Success, we have a packet */ | |
226 break; | |
227 default: | |
228 av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed [%d]\n", result); | |
229 return -1; | |
230 } | |
231 | |
232 /* Copy ogg_packet content out to buffer */ | |
233 if (buf_size < o_packet.bytes) { | |
234 av_log(avc_context, AV_LOG_ERROR, "encoded frame too large\n"); | |
235 return -1; | |
236 } | |
237 memcpy(outbuf, o_packet.packet, o_packet.bytes); | |
238 | |
239 return o_packet.bytes; | |
240 } | |
241 | |
242 static int encode_close(AVCodecContext* avc_context) | |
243 { | |
244 ogg_packet o_packet; | |
245 TheoraContext *h = avc_context->priv_data; | |
246 int result; | |
247 const char* message; | |
248 | |
249 result = theora_encode_packetout( &(h->t_state), 1, &o_packet ); | |
250 theora_clear( &(h->t_state) ); | |
251 switch (result) { | |
252 case 0:/* No packet is ready */ | |
253 case -1:/* Encoding finished */ | |
254 return 0; | |
255 case 1: | |
256 /* We have a packet */ | |
257 message = "gave us a packet"; | |
258 break; | |
259 default: | |
260 message = "unknown reason"; | |
261 break; | |
262 } | |
263 av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed (%s) [%d]\n", message, result); | |
264 return -1; | |
265 } | |
266 | |
6788 | 267 static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; |
4403 | 268 |
269 /*! AVCodec struct exposed to libavcodec */ | |
270 AVCodec libtheora_encoder = | |
271 { | |
272 .name = "libtheora", | |
273 .type = CODEC_TYPE_VIDEO, | |
274 .id = CODEC_ID_THEORA, | |
275 .priv_data_size = sizeof(TheoraContext), | |
276 .init = encode_init, | |
277 .close = encode_close, | |
278 .encode = encode_frame, | |
279 .pix_fmts = supported_pixel_formats, | |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6788
diff
changeset
|
280 .long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"), |
4403 | 281 }; |