comparison libtheoraenc.c @ 10554:deabe9f7571b libavcodec

Add support for two pass encoding in libtheora
author conrad
date Sun, 22 Nov 2009 21:08:40 +0000
parents 86c7e3c6de00
children 3d8ab953a869
comparison
equal deleted inserted replaced
10553:86c7e3c6de00 10554:deabe9f7571b
31 */ 31 */
32 32
33 /* FFmpeg includes */ 33 /* FFmpeg includes */
34 #include "libavutil/intreadwrite.h" 34 #include "libavutil/intreadwrite.h"
35 #include "libavutil/log.h" 35 #include "libavutil/log.h"
36 #include "libavutil/base64.h"
36 #include "avcodec.h" 37 #include "avcodec.h"
37 38
38 /* libtheora includes */ 39 /* libtheora includes */
39 #include <theora/theoraenc.h> 40 #include <theora/theoraenc.h>
40 41
41 typedef struct TheoraContext { 42 typedef struct TheoraContext {
42 th_enc_ctx *t_state; 43 th_enc_ctx *t_state;
44 uint8_t *stats;
45 int stats_size;
46 int stats_offset;
43 } TheoraContext; 47 } TheoraContext;
44 48
45 /*! 49 /*!
46 Concatenates an ogg_packet into the extradata. 50 Concatenates an ogg_packet into the extradata.
47 */ 51 */
73 avc_context->extradata_size = newsize; 77 avc_context->extradata_size = newsize;
74 AV_WB16(avc_context->extradata + (*offset), packet->bytes); 78 AV_WB16(avc_context->extradata + (*offset), packet->bytes);
75 *offset += 2; 79 *offset += 2;
76 memcpy(avc_context->extradata + (*offset), packet->packet, packet->bytes); 80 memcpy(avc_context->extradata + (*offset), packet->packet, packet->bytes);
77 (*offset) += packet->bytes; 81 (*offset) += packet->bytes;
82 return 0;
83 }
84
85 static int get_stats(AVCodecContext *avctx, int eos)
86 {
87 TheoraContext *h = avctx->priv_data;
88 uint8_t *buf;
89 int bytes;
90
91 bytes = th_encode_ctl(h->t_state, TH_ENCCTL_2PASS_OUT, &buf, sizeof(buf));
92 if (bytes < 0) {
93 av_log(avctx, AV_LOG_ERROR, "Error getting first pass stats\n");
94 return -1;
95 }
96 if (!eos) {
97 h->stats = av_fast_realloc(h->stats, &h->stats_size,
98 h->stats_offset + bytes);
99 memcpy(h->stats + h->stats_offset, buf, bytes);
100 h->stats_offset += bytes;
101 } else {
102 int b64_size = ((h->stats_offset + 2) / 3) * 4 + 1;
103 // libtheora generates a summary header at the end
104 memcpy(h->stats, buf, bytes);
105 avctx->stats_out = av_malloc(b64_size);
106 av_base64_encode(avctx->stats_out, b64_size, h->stats, h->stats_offset);
107 }
108 return 0;
109 }
110
111 // libtheora won't read the entire buffer we give it at once, so we have to
112 // repeatedly submit it...
113 static int submit_stats(AVCodecContext *avctx)
114 {
115 TheoraContext *h = avctx->priv_data;
116 int bytes;
117 if (!h->stats) {
118 if (!avctx->stats_in) {
119 av_log(avctx, AV_LOG_ERROR, "No statsfile for second pass\n");
120 return -1;
121 }
122 h->stats_size = strlen(avctx->stats_in) * 3/4;
123 h->stats = av_malloc(h->stats_size);
124 h->stats_size = av_base64_decode(h->stats, avctx->stats_in, h->stats_size);
125 }
126 while (h->stats_size - h->stats_offset > 0) {
127 bytes = th_encode_ctl(h->t_state, TH_ENCCTL_2PASS_IN,
128 h->stats + h->stats_offset,
129 h->stats_size - h->stats_offset);
130 if (bytes < 0) {
131 av_log(avctx, AV_LOG_ERROR, "Error submitting stats\n");
132 return -1;
133 }
134 if (!bytes)
135 return 0;
136 h->stats_offset += bytes;
137 }
78 return 0; 138 return 0;
79 } 139 }
80 140
81 static av_cold int encode_init(AVCodecContext* avc_context) 141 static av_cold int encode_init(AVCodecContext* avc_context)
82 { 142 {
136 &gop_size, sizeof(gop_size))) { 196 &gop_size, sizeof(gop_size))) {
137 av_log(avc_context, AV_LOG_ERROR, "Error setting GOP size\n"); 197 av_log(avc_context, AV_LOG_ERROR, "Error setting GOP size\n");
138 return -1; 198 return -1;
139 } 199 }
140 200
201 // need to enable 2 pass (via TH_ENCCTL_2PASS_) before encoding headers
202 if (avc_context->flags & CODEC_FLAG_PASS1) {
203 if (get_stats(avc_context, 0))
204 return -1;
205 } else if (avc_context->flags & CODEC_FLAG_PASS2) {
206 if (submit_stats(avc_context))
207 return -1;
208 }
209
141 /* 210 /*
142 Output first header packet consisting of theora 211 Output first header packet consisting of theora
143 header, comment, and tables. 212 header, comment, and tables.
144 213
145 Each one is prefixed with a 16bit size, then they 214 Each one is prefixed with a 16bit size, then they
170 AVFrame *frame = data; 239 AVFrame *frame = data;
171 ogg_packet o_packet; 240 ogg_packet o_packet;
172 int result, i; 241 int result, i;
173 242
174 assert(avc_context->pix_fmt == PIX_FMT_YUV420P); 243 assert(avc_context->pix_fmt == PIX_FMT_YUV420P);
244
245 // EOS, finish and get 1st pass stats if applicable
246 if (!frame) {
247 th_encode_packetout(h->t_state, 1, &o_packet);
248 if (avc_context->flags & CODEC_FLAG_PASS1)
249 if (get_stats(avc_context, 1))
250 return -1;
251 return 0;
252 }
175 253
176 /* Copy planes to the theora yuv_buffer */ 254 /* Copy planes to the theora yuv_buffer */
177 for (i = 0; i < 3; i++) { 255 for (i = 0; i < 3; i++) {
178 t_yuv_buffer[i].width = FFALIGN(avc_context->width, 16) >> !!i; 256 t_yuv_buffer[i].width = FFALIGN(avc_context->width, 16) >> !!i;
179 t_yuv_buffer[i].height = FFALIGN(avc_context->height, 16) >> !!i; 257 t_yuv_buffer[i].height = FFALIGN(avc_context->height, 16) >> !!i;
180 t_yuv_buffer[i].stride = frame->linesize[i]; 258 t_yuv_buffer[i].stride = frame->linesize[i];
181 t_yuv_buffer[i].data = frame->data[i]; 259 t_yuv_buffer[i].data = frame->data[i];
182 } 260 }
261
262 if (avc_context->flags & CODEC_FLAG_PASS2)
263 if (submit_stats(avc_context))
264 return -1;
183 265
184 /* Now call into theora_encode_YUVin */ 266 /* Now call into theora_encode_YUVin */
185 result = th_encode_ycbcr_in(h->t_state, t_yuv_buffer); 267 result = th_encode_ycbcr_in(h->t_state, t_yuv_buffer);
186 if (result) { 268 if (result) {
187 const char* message; 269 const char* message;
198 } 280 }
199 av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result); 281 av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result);
200 return -1; 282 return -1;
201 } 283 }
202 284
285 if (avc_context->flags & CODEC_FLAG_PASS1)
286 if (get_stats(avc_context, 0))
287 return -1;
288
203 /* Pick up returned ogg_packet */ 289 /* Pick up returned ogg_packet */
204 result = th_encode_packetout(h->t_state, 0, &o_packet); 290 result = th_encode_packetout(h->t_state, 0, &o_packet);
205 switch (result) { 291 switch (result) {
206 case 0: 292 case 0:
207 /* No packet is ready */ 293 /* No packet is ready */
227 return o_packet.bytes; 313 return o_packet.bytes;
228 } 314 }
229 315
230 static av_cold int encode_close(AVCodecContext* avc_context) 316 static av_cold int encode_close(AVCodecContext* avc_context)
231 { 317 {
232 ogg_packet o_packet;
233 TheoraContext *h = avc_context->priv_data; 318 TheoraContext *h = avc_context->priv_data;
234 int result; 319
235 const char* message;
236
237 result = th_encode_packetout(h->t_state, 1, &o_packet);
238 th_encode_free(h->t_state); 320 th_encode_free(h->t_state);
321 av_freep(&h->stats);
239 av_freep(&avc_context->coded_frame); 322 av_freep(&avc_context->coded_frame);
323 av_freep(&avc_context->stats_out);
240 av_freep(&avc_context->extradata); 324 av_freep(&avc_context->extradata);
241 avc_context->extradata_size = 0; 325 avc_context->extradata_size = 0;
242 326
243 switch (result) { 327 return 0;
244 case 0: /* No packet is ready */
245 case -1: /* Encoding finished */
246 return 0;
247 case 1:
248 /* We have a packet */
249 message = "gave us a packet";
250 break;
251 default:
252 message = "unknown reason";
253 break;
254 }
255 av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed (%s) [%d]\n", message, result);
256 return -1;
257 } 328 }
258 329
259 static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; 330 static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
260 331
261 /*! AVCodec struct exposed to libavcodec */ 332 /*! AVCodec struct exposed to libavcodec */
265 .id = CODEC_ID_THEORA, 336 .id = CODEC_ID_THEORA,
266 .priv_data_size = sizeof(TheoraContext), 337 .priv_data_size = sizeof(TheoraContext),
267 .init = encode_init, 338 .init = encode_init,
268 .close = encode_close, 339 .close = encode_close,
269 .encode = encode_frame, 340 .encode = encode_frame,
341 .capabilities = CODEC_CAP_DELAY, // needed to get the statsfile summary
270 .pix_fmts = supported_pixel_formats, 342 .pix_fmts = supported_pixel_formats,
271 .long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"), 343 .long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"),
272 }; 344 };