|
|
@@ -48,6 +48,9 @@ |
|
|
|
#include <stdarg.h> |
|
|
|
#include <limits.h> |
|
|
|
#include <float.h> |
|
|
|
#if HAVE_ICONV |
|
|
|
# include <iconv.h> |
|
|
|
#endif |
|
|
|
|
|
|
|
volatile int ff_avcodec_locked; |
|
|
|
static int volatile entangled_thread_counter = 0; |
|
|
@@ -1089,6 +1092,32 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code |
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
goto free_and_end; |
|
|
|
} |
|
|
|
if (avctx->sub_charenc) { |
|
|
|
if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Character encoding is only " |
|
|
|
"supported with subtitles codecs\n"); |
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
goto free_and_end; |
|
|
|
} else if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB) { |
|
|
|
av_log(avctx, AV_LOG_WARNING, "Codec '%s' is bitmap-based, " |
|
|
|
"subtitles character encoding will be ignored\n", |
|
|
|
avctx->codec_descriptor->name); |
|
|
|
avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_DO_NOTHING; |
|
|
|
} else { |
|
|
|
/* input character encoding is set for a text based subtitle |
|
|
|
* codec at this point */ |
|
|
|
if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_AUTOMATIC) |
|
|
|
avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_PRE_DECODER; |
|
|
|
|
|
|
|
if (!HAVE_ICONV && avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_PRE_DECODER) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Character encoding subtitles " |
|
|
|
"conversion needs a libavcodec built with iconv support " |
|
|
|
"for this codec\n"); |
|
|
|
ret = AVERROR(ENOSYS); |
|
|
|
goto free_and_end; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
end: |
|
|
|
ff_unlock_avcodec(); |
|
|
@@ -1847,6 +1876,68 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx, |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
#define UTF8_MAX_BYTES 4 /* 5 and 6 bytes sequences should not be used */ |
|
|
|
static int recode_subtitle(AVCodecContext *avctx, |
|
|
|
AVPacket *outpkt, const AVPacket *inpkt) |
|
|
|
{ |
|
|
|
#if HAVE_ICONV |
|
|
|
iconv_t cd = (iconv_t)-1; |
|
|
|
int ret = 0; |
|
|
|
char *inb, *outb; |
|
|
|
size_t inl, outl; |
|
|
|
AVPacket tmp; |
|
|
|
#endif |
|
|
|
|
|
|
|
if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_PRE_DECODER) |
|
|
|
return 0; |
|
|
|
|
|
|
|
#if HAVE_ICONV |
|
|
|
cd = iconv_open("UTF-8", avctx->sub_charenc); |
|
|
|
if (cd == (iconv_t)-1) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to open iconv context " |
|
|
|
"with input character encoding \"%s\"\n", avctx->sub_charenc); |
|
|
|
ret = AVERROR(errno); |
|
|
|
goto end; |
|
|
|
} |
|
|
|
|
|
|
|
inb = inpkt->data; |
|
|
|
inl = inpkt->size; |
|
|
|
|
|
|
|
if (inl >= INT_MAX / UTF8_MAX_BYTES - FF_INPUT_BUFFER_PADDING_SIZE) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Subtitles packet is too big for recoding\n"); |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
|
goto end; |
|
|
|
} |
|
|
|
|
|
|
|
ret = av_new_packet(&tmp, inl * UTF8_MAX_BYTES); |
|
|
|
if (ret < 0) |
|
|
|
goto end; |
|
|
|
outpkt->data = tmp.data; |
|
|
|
outpkt->size = tmp.size; |
|
|
|
outb = outpkt->data; |
|
|
|
outl = outpkt->size; |
|
|
|
|
|
|
|
if (iconv(cd, &inb, &inl, &outb, &outl) == (size_t)-1 || |
|
|
|
iconv(cd, NULL, NULL, &outb, &outl) == (size_t)-1 || |
|
|
|
outl >= outpkt->size || inl != 0) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to recode subtitle event \"%s\" " |
|
|
|
"from %s to UTF-8\n", inpkt->data, avctx->sub_charenc); |
|
|
|
av_free_packet(&tmp); |
|
|
|
ret = AVERROR(errno); |
|
|
|
goto end; |
|
|
|
} |
|
|
|
outpkt->size -= outl; |
|
|
|
outpkt->data[outpkt->size - 1] = '\0'; |
|
|
|
|
|
|
|
end: |
|
|
|
if (cd != (iconv_t)-1) |
|
|
|
iconv_close(cd); |
|
|
|
return ret; |
|
|
|
#else |
|
|
|
av_assert0(!"requesting subtitles recoding without iconv"); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, |
|
|
|
int *got_sub_ptr, |
|
|
|
AVPacket *avpkt) |
|
|
@@ -1862,19 +1953,28 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, |
|
|
|
avcodec_get_subtitle_defaults(sub); |
|
|
|
|
|
|
|
if (avpkt->size) { |
|
|
|
AVPacket pkt_recoded; |
|
|
|
AVPacket tmp = *avpkt; |
|
|
|
int did_split = av_packet_split_side_data(&tmp); |
|
|
|
//apply_param_change(avctx, &tmp); |
|
|
|
|
|
|
|
avctx->pkt = &tmp; |
|
|
|
pkt_recoded = tmp; |
|
|
|
ret = recode_subtitle(avctx, &pkt_recoded, &tmp); |
|
|
|
if (ret < 0) { |
|
|
|
*got_sub_ptr = 0; |
|
|
|
} else { |
|
|
|
avctx->pkt = &pkt_recoded; |
|
|
|
|
|
|
|
if (avctx->pkt_timebase.den && avpkt->pts != AV_NOPTS_VALUE) |
|
|
|
sub->pts = av_rescale_q(avpkt->pts, |
|
|
|
avctx->pkt_timebase, AV_TIME_BASE_Q); |
|
|
|
ret = avctx->codec->decode(avctx, sub, got_sub_ptr, &tmp); |
|
|
|
ret = avctx->codec->decode(avctx, sub, got_sub_ptr, &pkt_recoded); |
|
|
|
if (tmp.data != pkt_recoded.data) |
|
|
|
av_free(pkt_recoded.data); |
|
|
|
sub->format = !(avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB); |
|
|
|
|
|
|
|
avctx->pkt = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
if (did_split) { |
|
|
|
ff_packet_free_side_data(&tmp); |
|
|
|
if(ret == tmp.size) |
|
|
|