diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c index 8ce375c260..4b65e52859 100644 --- a/gst/isomp4/atoms.c +++ b/gst/isomp4/atoms.c @@ -486,6 +486,38 @@ sample_entry_mp4v_new (AtomsContext * context) return mp4v; } +static void +sample_entry_tx3g_init (SampleTableEntryTX3G * tx3g) +{ + atom_sample_entry_init (&tx3g->se, FOURCC_tx3g); + + tx3g->display_flags = 0; + tx3g->font_id = 1; /* must be 1 as there is a single font */ + tx3g->font_face = 0; + tx3g->foreground_color_rgba = 0xFFFFFFFF; /* white, opaque */ + + /* can't set this now */ + tx3g->default_text_box = 0; + tx3g->font_size = 0; +} + +static void +sample_entry_tx3g_free (SampleTableEntryTX3G * tx3g) +{ + atom_sample_entry_free (&tx3g->se); + g_free (tx3g); +} + +static SampleTableEntryTX3G * +sample_entry_tx3g_new (void) +{ + SampleTableEntryTX3G *tx3g = g_new0 (SampleTableEntryTX3G, 1); + + sample_entry_tx3g_init (tx3g); + return tx3g; +} + + static void atom_stsd_init (AtomSTSD * stsd) { @@ -516,6 +548,9 @@ atom_stsd_remove_entries (AtomSTSD * stsd) case VIDEO: sample_entry_mp4v_free ((SampleTableEntryMP4V *) se); break; + case SUBTITLE: + sample_entry_tx3g_free ((SampleTableEntryTX3G *) se); + break; default: /* best possible cleanup */ atom_sample_entry_free (se); @@ -1795,6 +1830,48 @@ sample_entry_mp4v_copy_data (SampleTableEntryMP4V * mp4v, guint8 ** buffer, return *offset - original_offset; } +static guint64 +sample_entry_tx3g_copy_data (SampleTableEntryTX3G * tx3g, guint8 ** buffer, + guint64 * size, guint64 * offset) +{ + guint64 original_offset = *offset; + + if (!atom_sample_entry_copy_data (&tx3g->se, buffer, size, offset)) { + return 0; + } + + prop_copy_uint32 (tx3g->display_flags, buffer, size, offset); + + /* reserved */ + prop_copy_uint8 (1, buffer, size, offset); + prop_copy_uint8 (-1, buffer, size, offset); + prop_copy_uint32 (0, buffer, size, offset); + + prop_copy_uint64 (tx3g->default_text_box, buffer, size, offset); + + /* reserved */ + prop_copy_uint32 (0, buffer, size, offset); + + prop_copy_uint16 (tx3g->font_id, buffer, size, offset); + prop_copy_uint8 (tx3g->font_face, buffer, size, offset); + prop_copy_uint8 (tx3g->font_size, buffer, size, offset); + prop_copy_uint32 (tx3g->foreground_color_rgba, buffer, size, offset); + + /* it must have a fonttable atom */ + { + Atom atom; + + atom_header_set (&atom, FOURCC_ftab, 18, 0); + atom_copy_data (&atom, buffer, size, offset); + prop_copy_uint16 (1, buffer, size, offset); /* Count must be 1 */ + prop_copy_uint16 (1, buffer, size, offset); /* Font id: 1 */ + prop_copy_size_string ((guint8 *) "Serif", 5, buffer, size, offset); + } + + atom_write_size (buffer, size, offset, original_offset); + return *offset - original_offset; +} + guint64 atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size, guint64 * offset) @@ -1985,6 +2062,11 @@ atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size, walker->data, buffer, size, offset)) { return 0; } + } else if (se->kind == SUBTITLE) { + if (!sample_entry_tx3g_copy_data ((SampleTableEntryTX3G *) + walker->data, buffer, size, offset)) { + return 0; + } } else { if (!atom_hint_sample_entry_copy_data ( (AtomHintSampleEntry *) walker->data, buffer, size, offset)) { @@ -2826,6 +2908,40 @@ atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate, } } +void +atom_trak_tx3g_update_dimension (AtomTRAK * trak, guint32 width, guint32 height) +{ + AtomSTSD *stsd; + GList *iter; + SampleTableEntryTX3G *tx3g = NULL; + + stsd = &trak->mdia.minf.stbl.stsd; + for (iter = stsd->entries; iter && tx3g == NULL; iter = g_list_next (iter)) { + SampleTableEntry *entry = iter->data; + + switch (entry->kind) { + case SUBTITLE:{ + tx3g = (SampleTableEntryTX3G *) entry; + break; + } + default: + break; + } + } + + /* Currently we never set the vertical placement flag, so we don't + * check for it to set the dimensions differently as the spec says. + * Always do it for the not set case */ + if (tx3g) { + tx3g->font_size = 0.05 * height; + + height = 0.15 * height; + trak->tkhd.width = width << 16; + trak->tkhd.height = height << 16; + tx3g->default_text_box = width | (height << 16); + } +} + /* * Meta tags functions */ @@ -3067,6 +3183,12 @@ atom_minf_set_video (AtomMINF * minf, AtomsContext * context) minf->vmhd = atom_vmhd_new (context); } +static void +atom_minf_set_subtitle (AtomMINF * minf) +{ + atom_minf_clear_handlers (minf); +} + static void atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type, guint32 hdlr_type) @@ -3103,6 +3225,15 @@ atom_mdia_set_hdlr_type_video (AtomMDIA * mdia, AtomsContext * context) atom_hdlr_set_name (&mdia->hdlr, "VideoHandler"); } +static void +atom_mdia_set_hdlr_type_subtitle (AtomMDIA * mdia, AtomsContext * context) +{ + atom_hdlr_set_type (&mdia->hdlr, context, FOURCC_mhlr, FOURCC_sbtl); + + /* Just follows the pattern from video and audio above */ + atom_hdlr_set_name (&mdia->hdlr, "SubtitleHandler"); +} + static void atom_mdia_set_audio (AtomMDIA * mdia, AtomsContext * context) { @@ -3117,6 +3248,13 @@ atom_mdia_set_video (AtomMDIA * mdia, AtomsContext * context) atom_minf_set_video (&mdia->minf, context); } +static void +atom_mdia_set_subtitle (AtomMDIA * mdia, AtomsContext * context) +{ + atom_mdia_set_hdlr_type_subtitle (mdia, context); + atom_minf_set_subtitle (&mdia->minf); +} + static void atom_tkhd_set_audio (AtomTKHD * tkhd) { @@ -3135,6 +3273,18 @@ atom_tkhd_set_video (AtomTKHD * tkhd, AtomsContext * context, guint32 width, tkhd->height = height; } +static void +atom_tkhd_set_subtitle (AtomTKHD * tkhd, AtomsContext * context, guint32 width, + guint32 height) +{ + tkhd->volume = 0; + + /* qt and ISO base media do not contradict, and examples agree */ + tkhd->width = width; + tkhd->height = height; +} + + static void atom_edts_add_entry (AtomEDTS * edts, EditListEntry * entry) { @@ -3205,6 +3355,23 @@ atom_trak_add_video_entry (AtomTRAK * trak, AtomsContext * context, return mp4v; } +static SampleTableEntryTX3G * +atom_trak_add_subtitle_entry (AtomTRAK * trak, AtomsContext * context, + guint32 type) +{ + SampleTableEntryTX3G *tx3g = sample_entry_tx3g_new (); + AtomSTSD *stsd = &trak->mdia.minf.stbl.stsd; + + tx3g->se.header.type = type; + tx3g->se.kind = SUBTITLE; + tx3g->se.data_reference_index = 1; + + stsd->entries = g_list_prepend (stsd->entries, tx3g); + stsd->n_entries++; + return tx3g; +} + + static void atom_trak_set_constant_size_samples (AtomTRAK * trak, guint32 sample_size) { @@ -3226,6 +3393,13 @@ atom_trak_set_video (AtomTRAK * trak, AtomsContext * context, guint32 width, atom_mdia_set_video (&trak->mdia, context); } +static void +atom_trak_set_subtitle (AtomTRAK * trak, AtomsContext * context) +{ + atom_tkhd_set_subtitle (&trak->tkhd, context, 0, 0); + atom_mdia_set_subtitle (&trak->mdia, context); +} + static void atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context, guint32 rate) @@ -3244,6 +3418,13 @@ atom_trak_set_video_commons (AtomTRAK * trak, AtomsContext * context, trak->tkhd.height = height << 16; } +static void +atom_trak_set_subtitle_commons (AtomTRAK * trak, AtomsContext * context) +{ + atom_trak_set_subtitle (trak, context); + trak->mdia.mdhd.time_info.timescale = 1000; +} + void atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context, AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size) @@ -3348,6 +3529,32 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, } } +void +subtitle_sample_entry_init (SubtitleSampleEntry * entry) +{ + entry->font_size = 0; + entry->font_face = 0; + entry->foreground_color_rgba = 0xFFFFFFFF; /* all white, opaque */ +} + +void +atom_trak_set_subtitle_type (AtomTRAK * trak, AtomsContext * context, + SubtitleSampleEntry * entry) +{ + SampleTableEntryTX3G *tx3g; + + atom_trak_set_subtitle_commons (trak, context); + atom_stsd_remove_entries (&trak->mdia.minf.stbl.stsd); + tx3g = atom_trak_add_subtitle_entry (trak, context, entry->fourcc); + + tx3g->font_face = entry->font_face; + tx3g->font_size = entry->font_size; + tx3g->foreground_color_rgba = entry->foreground_color_rgba; + + trak->is_video = FALSE; + trak->is_h264 = FALSE; +} + static void atom_mfhd_init (AtomMFHD * mfhd, guint32 sequence_number) { diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h index 887b53156b..b497074661 100644 --- a/gst/isomp4/atoms.h +++ b/gst/isomp4/atoms.h @@ -340,7 +340,8 @@ typedef enum _SampleEntryKind { UNKNOWN, AUDIO, - VIDEO + VIDEO, + SUBTITLE, } SampleEntryKind; typedef struct _SampleTableEntry @@ -350,7 +351,7 @@ typedef struct _SampleTableEntry guint8 reserved[6]; guint16 data_reference_index; - /* sort of entry */ + /* type of entry */ SampleEntryKind kind; } SampleTableEntry; @@ -421,6 +422,19 @@ typedef struct _SampleTableEntryMP4S AtomESDS es; } SampleTableEntryMP4S; +typedef struct _SampleTableEntryTX3G +{ + SampleTableEntry se; + + guint32 display_flags; + guint64 default_text_box; + guint16 font_id; + guint8 font_face; /* bold=0x1, italic=0x2, underline=0x4 */ + guint8 font_size; /* should always be 0.05 multiplied by the video track header height */ + guint32 foreground_color_rgba; + +} SampleTableEntryTX3G; + typedef struct _AtomSTSD { AtomFull header; @@ -899,6 +913,17 @@ typedef struct GstBuffer *codec_data; } AudioSampleEntry; +typedef struct +{ + guint32 fourcc; + + guint8 font_face; /* bold=0x1, italic=0x2, underline=0x4 */ + guint8 font_size; + guint32 foreground_color_rgba; +} SubtitleSampleEntry; + +void subtitle_sample_entry_init (SubtitleSampleEntry * entry); + void atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context, AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size); @@ -907,9 +932,15 @@ void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, VisualSampleEntry * entry, guint32 rate, GList * ext_atoms_list); +void atom_trak_set_subtitle_type (AtomTRAK * trak, AtomsContext * context, + SubtitleSampleEntry * entry); + void atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate, guint32 max_bitrate); +void atom_trak_tx3g_update_dimension (AtomTRAK * trak, guint32 width, + guint32 height); + AtomInfo * build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data); AtomInfo * build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data, guint32 avg_bitrate, guint32 max_bitrate); diff --git a/gst/isomp4/fourcc.h b/gst/isomp4/fourcc.h index ebbcdab98a..64322a7a75 100644 --- a/gst/isomp4/fourcc.h +++ b/gst/isomp4/fourcc.h @@ -120,6 +120,7 @@ G_BEGIN_DECLS #define FOURCC_free GST_MAKE_FOURCC('f','r','e','e') #define FOURCC_frma GST_MAKE_FOURCC('f','r','m','a') #define FOURCC_ftyp GST_MAKE_FOURCC('f','t','y','p') +#define FOURCC_ftab GST_MAKE_FOURCC('f','t','a','b') #define FOURCC_gama GST_MAKE_FOURCC('g','a','m','a') #define FOURCC_glbl GST_MAKE_FOURCC('g','l','b','l') #define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d')