X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Flibtheoraenc.c;h=e4ca721166596ba17be7d5f444ecca320e769a7c;hb=59bebb11e01981346c5e2f5b3e557a45ff89823f;hp=4ff30d68ff480ef4ba8dd6744e8cc36a8597642b;hpb=b0a6d9ca8629c934c43634a1538787c08f48ecc0;p=ffmpeg diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c index 4ff30d68ff4..e4ca7211665 100644 --- a/libavcodec/libtheoraenc.c +++ b/libavcodec/libtheoraenc.c @@ -18,10 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/*! - * \file libtheoraenc.c - * \brief Theora encoder using libtheora. - * \author Paul Richards +/** + * @file + * @brief Theora encoder using libtheora. + * @author Paul Richards * * A lot of this is copy / paste from other output codecs in * libavcodec or pure guesswork (or both). @@ -44,11 +44,12 @@ typedef struct TheoraContext { uint8_t *stats; int stats_size; int stats_offset; + int uv_hshift; + int uv_vshift; + int keyframe_mask; } TheoraContext; -/*! - Concatenates an ogg_packet into the extradata. -*/ +/** Concatenate an ogg_packet into the extradata. */ static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, const ogg_packet* packet) @@ -84,6 +85,7 @@ static int concatenate_packet(unsigned int* offset, static int get_stats(AVCodecContext *avctx, int eos) { +#ifdef TH_ENCCTL_2PASS_OUT TheoraContext *h = avctx->priv_data; uint8_t *buf; int bytes; @@ -99,19 +101,24 @@ static int get_stats(AVCodecContext *avctx, int eos) memcpy(h->stats + h->stats_offset, buf, bytes); h->stats_offset += bytes; } else { - int b64_size = ((h->stats_offset + 2) / 3) * 4 + 1; + int b64_size = AV_BASE64_SIZE(h->stats_offset); // libtheora generates a summary header at the end memcpy(h->stats, buf, bytes); avctx->stats_out = av_malloc(b64_size); av_base64_encode(avctx->stats_out, b64_size, h->stats, h->stats_offset); } return 0; +#else + av_log(avctx, AV_LOG_ERROR, "libtheora too old to support 2pass\n"); + return -1; +#endif } // libtheora won't read the entire buffer we give it at once, so we have to // repeatedly submit it... static int submit_stats(AVCodecContext *avctx) { +#ifdef TH_ENCCTL_2PASS_IN TheoraContext *h = avctx->priv_data; int bytes; if (!h->stats) { @@ -136,6 +143,10 @@ static int submit_stats(AVCodecContext *avctx) h->stats_offset += bytes; } return 0; +#else + av_log(avctx, AV_LOG_ERROR, "libtheora too old to support 2pass\n"); + return -1; +#endif } static av_cold int encode_init(AVCodecContext* avc_context) @@ -166,8 +177,25 @@ static av_cold int encode_init(AVCodecContext* avc_context) t_info.aspect_numerator = 1; t_info.aspect_denominator = 1; } - t_info.colorspace = TH_CS_UNSPECIFIED; - t_info.pixel_fmt = TH_PF_420; + + if (avc_context->color_primaries == AVCOL_PRI_BT470M) + t_info.colorspace = TH_CS_ITU_REC_470M; + else if (avc_context->color_primaries == AVCOL_PRI_BT470BG) + t_info.colorspace = TH_CS_ITU_REC_470BG; + else + t_info.colorspace = TH_CS_UNSPECIFIED; + + if (avc_context->pix_fmt == PIX_FMT_YUV420P) + t_info.pixel_fmt = TH_PF_420; + else if (avc_context->pix_fmt == PIX_FMT_YUV422P) + t_info.pixel_fmt = TH_PF_422; + else if (avc_context->pix_fmt == PIX_FMT_YUV444P) + t_info.pixel_fmt = TH_PF_444; + else { + av_log(avc_context, AV_LOG_ERROR, "Unsupported pix_fmt\n"); + return -1; + } + avcodec_get_chroma_sub_sample(avc_context->pix_fmt, &h->uv_hshift, &h->uv_vshift); if (avc_context->flags & CODEC_FLAG_QSCALE) { /* to be constant with the libvorbis implementation, clip global_quality to 0 - 10 @@ -189,6 +217,7 @@ static av_cold int encode_init(AVCodecContext* avc_context) return -1; } + h->keyframe_mask = (1 << t_info.keyframe_granule_shift) - 1; /* Clear up theora_info struct */ th_info_clear(&t_info); @@ -240,8 +269,6 @@ static int encode_frame(AVCodecContext* avc_context, uint8_t *outbuf, ogg_packet o_packet; int result, i; - assert(avc_context->pix_fmt == PIX_FMT_YUV420P); - // EOS, finish and get 1st pass stats if applicable if (!frame) { th_encode_packetout(h->t_state, 1, &o_packet); @@ -253,8 +280,8 @@ static int encode_frame(AVCodecContext* avc_context, uint8_t *outbuf, /* Copy planes to the theora yuv_buffer */ for (i = 0; i < 3; i++) { - t_yuv_buffer[i].width = FFALIGN(avc_context->width, 16) >> !!i; - t_yuv_buffer[i].height = FFALIGN(avc_context->height, 16) >> !!i; + t_yuv_buffer[i].width = FFALIGN(avc_context->width, 16) >> (i && h->uv_hshift); + t_yuv_buffer[i].height = FFALIGN(avc_context->height, 16) >> (i && h->uv_vshift); t_yuv_buffer[i].stride = frame->linesize[i]; t_yuv_buffer[i].data = frame->data[i]; } @@ -307,8 +334,10 @@ static int encode_frame(AVCodecContext* avc_context, uint8_t *outbuf, } memcpy(outbuf, o_packet.packet, o_packet.bytes); - // HACK: does not take codec delay into account (neither does the decoder though) + // HACK: assumes no encoder delay, this is true until libtheora becomes + // multithreaded (which will be disabled unless explictly requested) avc_context->coded_frame->pts = frame->pts; + avc_context->coded_frame->key_frame = !(o_packet.granulepos & h->keyframe_mask); return o_packet.bytes; } @@ -327,18 +356,16 @@ static av_cold int encode_close(AVCodecContext* avc_context) return 0; } -static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; - -/*! AVCodec struct exposed to libavcodec */ +/** AVCodec struct exposed to libavcodec */ AVCodec libtheora_encoder = { .name = "libtheora", - .type = CODEC_TYPE_VIDEO, + .type = AVMEDIA_TYPE_VIDEO, .id = CODEC_ID_THEORA, .priv_data_size = sizeof(TheoraContext), .init = encode_init, .close = encode_close, .encode = encode_frame, .capabilities = CODEC_CAP_DELAY, // needed to get the statsfile summary - .pix_fmts = supported_pixel_formats, + .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_NONE}, .long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"), };