qtmux: add support for the TX3G atoms

Adds functions for creating and setting values related to the
tx3g atom for raw text subtitle support.

QTFF spec has information on those atoms

https://bugzilla.gnome.org/show_bug.cgi?id=581295
This commit is contained in:
Thiago Santos 2014-02-06 12:09:01 -03:00
parent 2ae1897273
commit d644cda79b
3 changed files with 241 additions and 2 deletions

View file

@ -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)
{

View file

@ -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);

View file

@ -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')