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:
parent
2ae1897273
commit
d644cda79b
@ -486,6 +486,38 @@ sample_entry_mp4v_new (AtomsContext * context)
|
|||||||
return mp4v;
|
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
|
static void
|
||||||
atom_stsd_init (AtomSTSD * stsd)
|
atom_stsd_init (AtomSTSD * stsd)
|
||||||
{
|
{
|
||||||
@ -516,6 +548,9 @@ atom_stsd_remove_entries (AtomSTSD * stsd)
|
|||||||
case VIDEO:
|
case VIDEO:
|
||||||
sample_entry_mp4v_free ((SampleTableEntryMP4V *) se);
|
sample_entry_mp4v_free ((SampleTableEntryMP4V *) se);
|
||||||
break;
|
break;
|
||||||
|
case SUBTITLE:
|
||||||
|
sample_entry_tx3g_free ((SampleTableEntryTX3G *) se);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* best possible cleanup */
|
/* best possible cleanup */
|
||||||
atom_sample_entry_free (se);
|
atom_sample_entry_free (se);
|
||||||
@ -1795,6 +1830,48 @@ sample_entry_mp4v_copy_data (SampleTableEntryMP4V * mp4v, guint8 ** buffer,
|
|||||||
return *offset - original_offset;
|
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
|
guint64
|
||||||
atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
|
atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
|
||||||
guint64 * offset)
|
guint64 * offset)
|
||||||
@ -1985,6 +2062,11 @@ atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size,
|
|||||||
walker->data, buffer, size, offset)) {
|
walker->data, buffer, size, offset)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else if (se->kind == SUBTITLE) {
|
||||||
|
if (!sample_entry_tx3g_copy_data ((SampleTableEntryTX3G *)
|
||||||
|
walker->data, buffer, size, offset)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!atom_hint_sample_entry_copy_data (
|
if (!atom_hint_sample_entry_copy_data (
|
||||||
(AtomHintSampleEntry *) walker->data, buffer, size, offset)) {
|
(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
|
* Meta tags functions
|
||||||
*/
|
*/
|
||||||
@ -3067,6 +3183,12 @@ atom_minf_set_video (AtomMINF * minf, AtomsContext * context)
|
|||||||
minf->vmhd = atom_vmhd_new (context);
|
minf->vmhd = atom_vmhd_new (context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
atom_minf_set_subtitle (AtomMINF * minf)
|
||||||
|
{
|
||||||
|
atom_minf_clear_handlers (minf);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type,
|
atom_hdlr_set_type (AtomHDLR * hdlr, AtomsContext * context, guint32 comp_type,
|
||||||
guint32 hdlr_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");
|
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
|
static void
|
||||||
atom_mdia_set_audio (AtomMDIA * mdia, AtomsContext * context)
|
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);
|
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
|
static void
|
||||||
atom_tkhd_set_audio (AtomTKHD * tkhd)
|
atom_tkhd_set_audio (AtomTKHD * tkhd)
|
||||||
{
|
{
|
||||||
@ -3135,6 +3273,18 @@ atom_tkhd_set_video (AtomTKHD * tkhd, AtomsContext * context, guint32 width,
|
|||||||
tkhd->height = height;
|
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
|
static void
|
||||||
atom_edts_add_entry (AtomEDTS * edts, EditListEntry * entry)
|
atom_edts_add_entry (AtomEDTS * edts, EditListEntry * entry)
|
||||||
{
|
{
|
||||||
@ -3205,6 +3355,23 @@ atom_trak_add_video_entry (AtomTRAK * trak, AtomsContext * context,
|
|||||||
return mp4v;
|
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
|
static void
|
||||||
atom_trak_set_constant_size_samples (AtomTRAK * trak, guint32 sample_size)
|
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);
|
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
|
static void
|
||||||
atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context,
|
atom_trak_set_audio_commons (AtomTRAK * trak, AtomsContext * context,
|
||||||
guint32 rate)
|
guint32 rate)
|
||||||
@ -3244,6 +3418,13 @@ atom_trak_set_video_commons (AtomTRAK * trak, AtomsContext * context,
|
|||||||
trak->tkhd.height = height << 16;
|
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
|
void
|
||||||
atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
|
atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
|
||||||
AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size)
|
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
|
static void
|
||||||
atom_mfhd_init (AtomMFHD * mfhd, guint32 sequence_number)
|
atom_mfhd_init (AtomMFHD * mfhd, guint32 sequence_number)
|
||||||
{
|
{
|
||||||
|
@ -340,7 +340,8 @@ typedef enum _SampleEntryKind
|
|||||||
{
|
{
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
AUDIO,
|
AUDIO,
|
||||||
VIDEO
|
VIDEO,
|
||||||
|
SUBTITLE,
|
||||||
} SampleEntryKind;
|
} SampleEntryKind;
|
||||||
|
|
||||||
typedef struct _SampleTableEntry
|
typedef struct _SampleTableEntry
|
||||||
@ -350,7 +351,7 @@ typedef struct _SampleTableEntry
|
|||||||
guint8 reserved[6];
|
guint8 reserved[6];
|
||||||
guint16 data_reference_index;
|
guint16 data_reference_index;
|
||||||
|
|
||||||
/* sort of entry */
|
/* type of entry */
|
||||||
SampleEntryKind kind;
|
SampleEntryKind kind;
|
||||||
} SampleTableEntry;
|
} SampleTableEntry;
|
||||||
|
|
||||||
@ -421,6 +422,19 @@ typedef struct _SampleTableEntryMP4S
|
|||||||
AtomESDS es;
|
AtomESDS es;
|
||||||
} SampleTableEntryMP4S;
|
} 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
|
typedef struct _AtomSTSD
|
||||||
{
|
{
|
||||||
AtomFull header;
|
AtomFull header;
|
||||||
@ -899,6 +913,17 @@ typedef struct
|
|||||||
GstBuffer *codec_data;
|
GstBuffer *codec_data;
|
||||||
} AudioSampleEntry;
|
} 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,
|
void atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context,
|
||||||
AudioSampleEntry * entry, guint32 scale,
|
AudioSampleEntry * entry, guint32 scale,
|
||||||
AtomInfo * ext, gint sample_size);
|
AtomInfo * ext, gint sample_size);
|
||||||
@ -907,9 +932,15 @@ void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context,
|
|||||||
VisualSampleEntry * entry, guint32 rate,
|
VisualSampleEntry * entry, guint32 rate,
|
||||||
GList * ext_atoms_list);
|
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,
|
void atom_trak_update_bitrates (AtomTRAK * trak, guint32 avg_bitrate,
|
||||||
guint32 max_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_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data);
|
||||||
AtomInfo * build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data,
|
AtomInfo * build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data,
|
||||||
guint32 avg_bitrate, guint32 max_bitrate);
|
guint32 avg_bitrate, guint32 max_bitrate);
|
||||||
|
@ -120,6 +120,7 @@ G_BEGIN_DECLS
|
|||||||
#define FOURCC_free GST_MAKE_FOURCC('f','r','e','e')
|
#define FOURCC_free GST_MAKE_FOURCC('f','r','e','e')
|
||||||
#define FOURCC_frma GST_MAKE_FOURCC('f','r','m','a')
|
#define FOURCC_frma GST_MAKE_FOURCC('f','r','m','a')
|
||||||
#define FOURCC_ftyp GST_MAKE_FOURCC('f','t','y','p')
|
#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_gama GST_MAKE_FOURCC('g','a','m','a')
|
||||||
#define FOURCC_glbl GST_MAKE_FOURCC('g','l','b','l')
|
#define FOURCC_glbl GST_MAKE_FOURCC('g','l','b','l')
|
||||||
#define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d')
|
#define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user