[xiph-commits] r17294 - in trunk/ffmpeg2theora: . src
oggk at svn.xiph.org
oggk at svn.xiph.org
Thu Jun 17 08:06:37 PDT 2010
Author: oggk
Date: 2010-06-17 08:06:37 -0700 (Thu, 17 Jun 2010)
New Revision: 17294
Modified:
trunk/ffmpeg2theora/ffmpeg2theora.1
trunk/ffmpeg2theora/src/ffmpeg2theora.c
trunk/ffmpeg2theora/src/ffmpeg2theora.h
trunk/ffmpeg2theora/src/subtitles.c
trunk/ffmpeg2theora/src/subtitles.h
trunk/ffmpeg2theora/src/theorautils.c
trunk/ffmpeg2theora/src/theorautils.h
trunk/ffmpeg2theora/subtitles.txt
Log:
SPU style subtitles (eg, those found on DVDs) are now supported as well, though not
enabled by default; OKed by j.
Modified: trunk/ffmpeg2theora/ffmpeg2theora.1
===================================================================
--- trunk/ffmpeg2theora/ffmpeg2theora.1 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/ffmpeg2theora.1 2010-06-17 15:06:37 UTC (rev 17294)
@@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
-.TH FFMPEG2THEORA 1 "July 31, 2009"
+.TH FFMPEG2THEORA 1 "May 14, 2010"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -231,6 +231,14 @@
Disables subtitles from input.
Note that subtitles explicitely loaded from external files will still
be used.
+.TP
+.B \-\-subtitle-types
+Selects which subtitle types to include from the input file.
+Allowed types are: none, all, text, spu (spu being the image based
+subtitles found on DVD).
+By default, only text based subtitles will be included.
+Note that subtitles explicitely loaded from external files will still
+be used.
.SS Metadata options:
.TP
.B \-\-artist
Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.c 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.c 2010-06-17 15:06:37 UTC (rev 17294)
@@ -61,6 +61,7 @@
NOAUDIO_FLAG,
NOVIDEO_FLAG,
NOSUBTITLES_FLAG,
+ SUBTITLETYPES_FLAG,
NOMETADATA_FLAG,
NOOSHASH_FLAG,
NOUPSCALING_FLAG,
@@ -113,6 +114,8 @@
#define NTSC_FULL_WIDTH 720
#define NTSC_FULL_HEIGHT 480
+#define INCSUB_TEXT 1
+#define INCSUB_SPU 2
oggmux_info info;
@@ -167,7 +170,7 @@
if (this != NULL) {
this->disable_audio=0;
this->disable_video=0;
- this->disable_subtitles=0;
+ this->included_subtitles=INCSUB_TEXT;
this->disable_metadata=0;
this->disable_oshash=0;
this->no_upscaling=0;
@@ -335,7 +338,7 @@
}
}
-static int is_supported_subtitle_stream(ff2theora this, int idx)
+static const char *find_category_for_subtitle_stream (ff2theora this, int idx, int included_subtitles)
{
AVCodecContext *enc = this->context->streams[idx]->codec;
if (enc->codec_type != CODEC_TYPE_SUBTITLE) return 0;
@@ -343,13 +346,26 @@
case CODEC_ID_TEXT:
case CODEC_ID_SSA:
case CODEC_ID_MOV_TEXT:
- return 1;
+ if (included_subtitles & INCSUB_TEXT)
+ return "SUB";
+ else
+ return NULL;
+ case CODEC_ID_DVD_SUBTITLE:
+ if (included_subtitles & INCSUB_SPU)
+ return "K-SPU";
+ else
+ return NULL;
default:
- return 0;
+ return NULL;
}
- return 0;
+ return NULL;
}
+static int is_supported_subtitle_stream(ff2theora this, int idx, int included_subtitles)
+{
+ return find_category_for_subtitle_stream(this, idx, included_subtitles) != NULL;
+}
+
static char *get_raw_text_from_ssa(const char *ssa)
{
int n,intag,inescape;
@@ -960,20 +976,22 @@
subtitles_enabled[i] = 0;
subtitles_opened[i] = 0;
#ifdef HAVE_KATE
- if (!this->disable_subtitles) {
+ if (this->included_subtitles) {
AVStream *stream = this->context->streams[i];
AVCodecContext *enc = stream->codec;
+ const char *category;
if (enc->codec_type == CODEC_TYPE_SUBTITLE) {
AVCodec *codec = avcodec_find_decoder (enc->codec_id);
if (codec && avcodec_open (enc, codec) >= 0) {
subtitles_opened[i] = 1;
}
- if (is_supported_subtitle_stream(this, i)) {
+ category = find_category_for_subtitle_stream(this, i, this->included_subtitles);
+ if (category) {
subtitles_enabled[i] = 1;
- add_subtitles_stream(this, i, find_language_for_subtitle_stream(stream), NULL);
+ add_subtitles_stream(this, i, find_language_for_subtitle_stream(stream), category);
}
else if(!info.frontend) {
- fprintf(stderr,"Subtitle stream %d codec not supported, ignored\n", i);
+ fprintf(stderr,"Subtitle stream %d, ignored\n", i);
}
}
}
@@ -990,7 +1008,7 @@
printf("Muxing Kate stream %d from input stream %d\n",
i,ks->stream_index);
#endif
- if (!this->disable_subtitles) {
+ if (this->included_subtitles) {
info.with_kate=1;
}
}
@@ -1265,6 +1283,8 @@
ki->gps_denominator = 1;
}
ki->granule_shift = 32;
+ ki->original_canvas_width = display_width;
+ ki->original_canvas_height = display_height;
}
}
}
@@ -1536,7 +1556,7 @@
}
if (info.passno!=1)
- if (!this->disable_subtitles && subtitles_enabled[pkt.stream_index] && is_supported_subtitle_stream(this, pkt.stream_index)) {
+ if (this->included_subtitles && subtitles_enabled[pkt.stream_index] && is_supported_subtitle_stream(this, pkt.stream_index, this->included_subtitles)) {
AVStream *stream=this->context->streams[pkt.stream_index];
AVCodecContext *enc = stream->codec;
if (enc) {
@@ -1546,9 +1566,11 @@
float t;
AVSubtitle sub;
int got_sub=0;
+ int64_t stream_start_time;
/* work out timing */
- t = (float)pkt.pts * stream->time_base.num / stream->time_base.den - this->start_time;
+ stream_start_time = stream->start_time == AV_NOPTS_VALUE ? 0 : stream->start_time;
+ t = (float)(pkt.pts - stream_start_time) * stream->time_base.num / stream->time_base.den - this->start_time;
// my test case has 0 duration, how clever of that. I assume it's that old 'ends whenever the next
// one starts' hack, but it means I don't know in advance what duration it has. Great!
float duration;
@@ -1562,13 +1584,40 @@
/* generic decoding */
if (enc->codec && avcodec_decode_subtitle2(enc,&sub,&got_sub,&pkt) >= 0) {
if (got_sub) {
- if (sub.rects[0]->ass) {
- extra_info_from_ssa(&pkt,&utf8,&utf8len,&allocated_utf8,&duration);
+ for (i=0; i<sub.num_rects; i++) {
+ const AVSubtitleRect *rect = sub.rects[i];
+ if (!rect) continue;
+
+ switch (rect->type) {
+ case SUBTITLE_TEXT:
+ if (!utf8) {
+ if (rect->text) {
+ utf8 = rect->text;
+ utf8len = strlen(utf8);
+ }
+ }
+ break;
+ case SUBTITLE_ASS:
+ /* text subtitles, only one for now */
+ if (!utf8) {
+ if (rect->ass) {
+ extra_info_from_ssa(&pkt,&utf8,&utf8len,&allocated_utf8,&duration);
+ }
+ else if (rect->text) {
+ utf8 = rect->text;
+ utf8len = strlen(utf8);
+ }
+ }
+ break;
+ case SUBTITLE_BITMAP:
+ /* image subtitles */
+ add_image_subtitle_for_stream(this->kate_streams, this->n_kate_streams, pkt.stream_index, t, duration, rect, display_width, display_height, info.frontend);
+ break;
+
+ default:
+ break;
+ }
}
- else if (sub.rects[0]->text) {
- utf8 = sub.rects[0]->text;
- utf8len = strlen(utf8);
- }
}
}
else if (enc->codec_id == CODEC_ID_TEXT) {
@@ -1633,7 +1682,14 @@
be held till the right time. If we don't do that, we can insert late and
oggz-validate moans */
while (ks->subtitles_count < ks->num_subtitles && sub->t0-1.0 <= avtime+this->start_time) {
- oggmux_add_kate_text(&info, i, sub->t0, sub->t1, sub->text, sub->len);
+#ifdef HAVE_KATE
+ if (sub->text) {
+ oggmux_add_kate_text(&info, i, sub->t0, sub->t1, sub->text, sub->len);
+ }
+ else {
+ oggmux_add_kate_image(&info, i, sub->t0, sub->t1, &sub->kr, &sub->kp, &sub->kb);
+ }
+#endif
ks->subtitles_count++;
++sub;
}
@@ -1648,6 +1704,7 @@
} while (ret >= 0 && !(audio_done && video_done));
if (info.passno != 1) {
+#ifdef HAVE_KATE
for (i=0; i<this->n_kate_streams; ++i) {
ff2theora_kate_stream *ks = this->kate_streams+i;
if (ks->num_subtitles > 0) {
@@ -1656,8 +1713,9 @@
oggmux_flush (&info, video_eos + audio_eos);
}
}
+#endif
- if (!this->disable_subtitles) {
+ if (this->included_subtitles) {
for (i = 0; i < this->context->nb_streams; i++) {
if (subtitles_opened[i]) {
AVCodecContext *enc = this->context->streams[i]->codec;
@@ -1978,6 +2036,9 @@
" --subtitles-category category set subtitles category (default \"subtitles\")\n"
" --subtitles-ignore-non-utf8 ignores any non UTF-8 sequence in UTF-8 text\n"
" --nosubtitles disables subtitles from input\n"
+ " (equivalent to --subtitles=none)\n"
+ " --subtitle-types=[all,text,spu,none] select what subtitle types to include from the\n"
+ " input video (default text)\n"
"\n"
#endif
"Metadata options:\n"
@@ -2089,6 +2150,7 @@
{"noaudio",0,&flag,NOAUDIO_FLAG},
{"novideo",0,&flag,NOVIDEO_FLAG},
{"nosubtitles",0,&flag,NOSUBTITLES_FLAG},
+ {"subtitle-types",required_argument,&flag,SUBTITLETYPES_FLAG},
{"nometadata",0,&flag,NOMETADATA_FLAG},
{"no-oshash",0,&flag,NOOSHASH_FLAG},
{"no-upscaling",0,&flag,NOUPSCALING_FLAG},
@@ -2233,9 +2295,29 @@
flag = -1;
break;
case NOSUBTITLES_FLAG:
- convert->disable_subtitles = 1;
+ convert->included_subtitles = 0;
flag = -1;
break;
+ case SUBTITLETYPES_FLAG:
+ if (!strcmp(optarg, "all")) {
+ convert->included_subtitles = INCSUB_TEXT | INCSUB_SPU;
+ }
+ else if (!strcmp(optarg, "none")) {
+ convert->included_subtitles = 0;
+ }
+ else if (!strcmp(optarg, "text")) {
+ convert->included_subtitles = INCSUB_TEXT;
+ }
+ else if (!strcmp(optarg, "spu")) {
+ convert->included_subtitles = INCSUB_SPU;
+ }
+ else {
+ fprintf(stderr,
+ "Subtitles to include must be all, none, text, or spu.\n");
+ exit(1);
+ }
+ flag = -1;
+ break;
case NOMETADATA_FLAG:
convert->disable_metadata = 1;
flag = -1;
@@ -2680,13 +2762,13 @@
switch (enc->codec_type) {
case CODEC_TYPE_VIDEO: has_video = 1; break;
case CODEC_TYPE_AUDIO: has_audio = 1; break;
- case CODEC_TYPE_SUBTITLE: if (is_supported_subtitle_stream(convert, i)) has_kate = 1; break;
+ case CODEC_TYPE_SUBTITLE: if (is_supported_subtitle_stream(convert, i, convert->included_subtitles)) has_kate = 1; break;
default: break;
}
}
has_video &= !convert->disable_video;
has_audio &= !convert->disable_audio;
- has_kate &= !convert->disable_subtitles;
+ has_kate &= !!convert->included_subtitles;
has_kate |= convert->n_kate_streams>0; /* may be added via command line */
has_skeleton |= info.with_skeleton;
@@ -2755,7 +2837,7 @@
if (convert->disable_video) {
fprintf(stderr, " [video disabled].\n");
}
- if (convert->disable_subtitles) {
+ if (!convert->included_subtitles) {
fprintf(stderr, " [subtitles disabled].\n");
}
if (convert->disable_metadata) {
Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.h
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.h 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.h 2010-06-17 15:06:37 UTC (rev 17294)
@@ -8,6 +8,11 @@
size_t len;
double t0;
double t1;
+#ifdef HAVE_KATE
+ kate_region kr;
+ kate_palette kp;
+ kate_bitmap kb;
+#endif
} ff2theora_subtitle;
typedef struct ff2theora_kate_stream{
@@ -46,7 +51,7 @@
int audio_bitrate;
int preset;
- int disable_subtitles;
+ int included_subtitles;
int disable_metadata;
int disable_oshash;
Modified: trunk/ffmpeg2theora/src/subtitles.c
===================================================================
--- trunk/ffmpeg2theora/src/subtitles.c 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/subtitles.c 2010-06-17 15:06:37 UTC (rev 17294)
@@ -530,6 +530,75 @@
return 0;
}
+int add_image_subtitle_for_stream(ff2theora_kate_stream *streams, int nstreams, int idx, float t, float duration, const AVSubtitleRect *sr, int org_width, int org_height, FILE *frontend)
+{
+#ifdef HAVE_KATE
+ int n, c, ret;
+ ff2theora_subtitle *subtitle;
+
+ if (sr->nb_colors <= 0 || sr->nb_colors > 256) {
+ warn(frontend, NULL, 0, "Unsupported number of colors in image subtitle: %d", sr->nb_colors);
+ return -1;
+ }
+
+ for (n=0; n<nstreams; ++n) {
+ ff2theora_kate_stream *ks=streams+n;
+ if (idx == ks->stream_index) {
+ ks->subtitles = (ff2theora_subtitle*)realloc(ks->subtitles, (ks->num_subtitles+1)*sizeof(ff2theora_subtitle));
+ if (!ks->subtitles) {
+ warn(frontend, NULL, 0, "Out of memory");
+ return -1;
+ }
+ subtitle = &ks->subtitles[ks->num_subtitles];
+
+ kate_region_init(&subtitle->kr);
+ subtitle->kr.metric = kate_millionths;
+ subtitle->kr.x = 1000000 * sr->x / org_width;
+ subtitle->kr.y = 1000000 * sr->y / org_height;
+ subtitle->kr.w = 1000000 * sr->w / org_width;
+ subtitle->kr.h = 1000000 * sr->h / org_height;
+
+ kate_palette_init(&subtitle->kp);
+ subtitle->kp.ncolors = sr->nb_colors;
+ subtitle->kp.colors = malloc(sizeof(kate_color) * subtitle->kp.ncolors);
+ if (!subtitle->kp.colors) {
+ warn(frontend, NULL, 0, "Out of memory");
+ return -1;
+ }
+ const uint32_t *pal = (const uint32_t*)sr->pict.data[1];
+ for (c=0; c<subtitle->kp.ncolors; ++c) {
+ subtitle->kp.colors[c].a = (pal[c]>>24)&0xff;
+ subtitle->kp.colors[c].r = (pal[c]>>16)&0xff;
+ subtitle->kp.colors[c].g = (pal[c]>>8)&0xff;
+ subtitle->kp.colors[c].b = pal[c]&0xff;
+ }
+
+ kate_bitmap_init(&subtitle->kb);
+ subtitle->kb.type = kate_bitmap_type_paletted;
+ subtitle->kb.width = sr->w;
+ subtitle->kb.height = sr->h;
+ subtitle->kb.bpp = 0;
+ while ((1<<subtitle->kb.bpp) < sr->nb_colors) ++subtitle->kb.bpp;
+ subtitle->kb.pixels = malloc(sr->w*sr->h);
+ if (!subtitle->kb.pixels) {
+ free(subtitle->kp.colors);
+ warn(frontend, NULL, 0, "Out of memory");
+ return -1;
+ }
+
+ /* Not quite sure if the AVPicture line data is supposed to always be packed */
+ memcpy(subtitle->kb.pixels,sr->pict.data[0],sr->w*sr->h);
+
+ subtitle->text = NULL;
+ subtitle->t0 = t;
+ subtitle->t1 = t+duration;
+ ks->num_subtitles++;
+ }
+ }
+#endif
+ return 0;
+}
+
void free_subtitles(ff2theora this)
{
size_t i,n;
Modified: trunk/ffmpeg2theora/src/subtitles.h
===================================================================
--- trunk/ffmpeg2theora/src/subtitles.h 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/subtitles.h 2010-06-17 15:06:37 UTC (rev 17294)
@@ -22,6 +22,7 @@
extern void add_subtitles_stream(ff2theora this,int stream_index,const char *language,const char *category);
extern int add_subtitle_for_stream(ff2theora_kate_stream *streams, int nstreams, int idx, float t, float duration, const char *utf8, size_t utf8len, FILE *frontend);
+extern int add_image_subtitle_for_stream(ff2theora_kate_stream *streams, int nstreams, int idx, float t, float duration, const AVSubtitleRect *sr, int org_width, int org_height, FILE *frontend);
extern void set_subtitles_file(ff2theora this,const char *filename);
extern void set_subtitles_language(ff2theora this,const char *language);
extern void set_subtitles_category(ff2theora this,const char *category);
Modified: trunk/ffmpeg2theora/src/theorautils.c
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.c 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/theorautils.c 2010-06-17 15:06:37 UTC (rev 17294)
@@ -1291,6 +1291,8 @@
ks->last_end_time = end_time;
}
+#ifdef HAVE_KATE
+
/**
* adds a subtitles text to the encoding sink
* if e_o_s is 1 the end of the logical bitstream will be marked.
@@ -1302,7 +1304,6 @@
* @param len the number of bytes in the text
*/
void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len) {
-#ifdef HAVE_KATE
ogg_packet op;
oggmux_kate_stream *ks=info->kate_streams+idx;
int ret;
@@ -1322,17 +1323,51 @@
fprintf(stderr, "Failed to encode kate data packet (%f --> %f, [%s]): %d\n",
t0, t1, text, ret);
}
-#endif
}
/**
+ * adds a subtitles image to the encoding sink
+ * if e_o_s is 1 the end of the logical bitstream will be marked.
+ * @param info oggmux_info
+ * @param idx which kate stream to output to
+ * @param t0 the show time of the text
+ * @param t1 the hide time of the text
+ * @param kr the region in which to display the subtitle
+ * @param kp the palette to use for the image
+ * @param kb the image itself
+ */
+void oggmux_add_kate_image (oggmux_info *info, int idx, double t0, double t1, const kate_region *kr, const kate_palette *kp, const kate_bitmap *kb) {
+ ogg_packet op;
+ oggmux_kate_stream *ks=info->kate_streams+idx;
+ int ret;
+ ret = kate_encode_set_region(&ks->k, kr);
+ if (ret >= 0) ret = kate_encode_set_palette(&ks->k, kp);
+ if (ret >= 0) ret = kate_encode_set_bitmap(&ks->k, kb);
+ if (ret >= 0) ret = kate_ogg_encode_text(&ks->k, t0, t1, "", 0, &op);
+ if (ret>=0) {
+ if (!info->skeleton_3 && info->passno != 1) {
+ ogg_int64_t start_time = (int)(t0 * 1000.0f + 0.5f);
+ ogg_int64_t end_time = (int)(t1 * 1000.0f + 0.5f);
+ oggmux_record_kate_index(info, ks, &op, start_time, end_time);
+ }
+
+ ogg_stream_packetin (&ks->ko, &op);
+ ogg_packet_clear (&op);
+ info->k_pkg++;
+ }
+ else {
+ fprintf(stderr, "Failed to encode kate data packet (%f --> %f, image): %d\n",
+ t0, t1, ret);
+ }
+}
+
+/**
* adds a kate end packet to the encoding sink
* @param info oggmux_info
* @param idx which kate stream to output to
* @param t the time of the end packet
*/
void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t) {
-#ifdef HAVE_KATE
ogg_packet op;
oggmux_kate_stream *ks=info->kate_streams+idx;
int ret;
@@ -1350,9 +1385,10 @@
else {
fprintf(stderr, "Failed to encode kate end packet at %f: %d\n", t, ret);
}
-#endif
}
+#endif
+
static double get_remaining(oggmux_info *info, double timebase) {
double remaining = 0;
double to_encode, time_so_far;
Modified: trunk/ffmpeg2theora/src/theorautils.h
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.h 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/src/theorautils.h 2010-06-17 15:06:37 UTC (rev 17294)
@@ -165,8 +165,11 @@
extern void oggmux_init (oggmux_info *info);
extern void oggmux_add_video (oggmux_info *info, th_ycbcr_buffer ycbcr, int e_o_s);
extern void oggmux_add_audio (oggmux_info *info, int16_t * readbuffer, int bytesread, int samplesread,int e_o_s);
+#ifdef HAVE_KATE
extern void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len);
+extern void oggmux_add_kate_image (oggmux_info *info, int idx, double t0, double t1, const kate_region *kr, const kate_palette *kp, const kate_bitmap *kb);
extern void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t);
+#endif
extern void oggmux_flush (oggmux_info *info, int e_o_s);
extern void oggmux_close (oggmux_info *info);
Modified: trunk/ffmpeg2theora/subtitles.txt
===================================================================
--- trunk/ffmpeg2theora/subtitles.txt 2010-06-16 22:32:53 UTC (rev 17293)
+++ trunk/ffmpeg2theora/subtitles.txt 2010-06-17 15:06:37 UTC (rev 17294)
@@ -77,8 +77,14 @@
Subtitle streams from the input file will not be converted. Subtitles
from any supplied --subtitles option will still be used.
+--subtitle-types <types>
+ By default, only text based subtitles found in the input file are
+ included in the output file. This option allows selecting which types
+ are to be included: none, all, text, or spu (spu being the type of
+ image-based subtitles found on DVDs).
+
* Converting non-UTF-8 files to UTF-8
If ffmpeg2theora wasn't build with iconv support, only UTF-8 and latin1
More information about the commits
mailing list