Mercurial > libavcodec.hg
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 }; |