Commit c991a04a authored by Thiago Sousa Santos's avatar Thiago Sousa Santos Committed by Tim-Philipp Müller

Copy qtmux from revision 148 of the gst-qtmux repository.

Original commit message from CVS:
patch by: Thiago Sousa Santos <thiagossantos@gmail.com>
* configure.ac:
* gst/quicktime/Makefile.am:
* gst/quicktime/atoms.c:
* gst/quicktime/atoms.h:
* gst/quicktime/descriptors.c:
* gst/quicktime/descriptors.h:
* gst/quicktime/fourcc.h:
* gst/quicktime/ftypcc.h:
* gst/quicktime/gstqtmux.c:
* gst/quicktime/gstqtmux.h:
* gst/quicktime/gstqtmuxmap.c:
* gst/quicktime/gstqtmuxmap.h:
* gst/quicktime/properties.c:
* gst/quicktime/properties.h:
Copy qtmux from revision 148 of the gst-qtmux repository.
Fixes #550280.
parent ed96310d
/* Quicktime muxer plugin for GStreamer
* Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
* Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "atoms.h"
#include <string.h>
#include <glib.h>
/* only needed for gst_util_uint64_scale */
#include <gst/gst.h>
/**
* Creates a new AtomsContext for the given flavor.
*/
AtomsContext *
atoms_context_new (AtomsTreeFlavor flavor)
{
AtomsContext *context = g_new0 (AtomsContext, 1);
context->flavor = flavor;
return context;
}
/**
* Frees an AtomsContext and all memory associated with it
*/
void
atoms_context_free (AtomsContext * context)
{
g_free (context);
}
/* -- creation, initialization, clear and free functions -- */
#define SECS_PER_DAY (24 * 60 * 60)
#define LEAP_YEARS_FROM_1904_TO_1970 17
static guint64
get_current_qt_time ()
{
GTimeVal timeval;
g_get_current_time (&timeval);
/* FIXME this should use UTC coordinated time */
return timeval.tv_sec + (((1970 - 1904) * (guint64) 365) +
LEAP_YEARS_FROM_1904_TO_1970) * SECS_PER_DAY;
}
static void
common_time_info_init (TimeInfo * ti)
{
ti->creation_time = ti->modification_time = get_current_qt_time ();
ti->timescale = 0;
ti->duration = 0;
}
static void
atom_header_set (Atom * header, guint32 fourcc, gint32 size, gint64 ext_size)
{
header->type = fourcc;
header->size = size;
header->extended_size = ext_size;
}
static void
atom_clear (Atom * atom)
{
}
static void
atom_full_init (AtomFull * full, guint32 fourcc, gint32 size, gint64 ext_size,
guint8 version, guint8 flags[3])
{
atom_header_set (&(full->header), fourcc, size, ext_size);
full->version = version;
full->flags[0] = flags[0];
full->flags[1] = flags[1];
full->flags[2] = flags[2];
}
static void
atom_full_clear (AtomFull * full)
{
atom_clear (&full->header);
}
static void
atom_full_free (AtomFull * full)
{
atom_full_clear (full);
g_free (full);
}
static AtomInfo *
build_atom_info_wrapper (Atom * atom, gpointer copy_func, gpointer free_func)
{
AtomInfo *info = NULL;
if (atom) {
info = g_new0 (AtomInfo, 1);
info->atom = atom;
info->copy_data_func = copy_func;
info->free_func = free_func;
}
return info;
}
static GList *
atom_info_list_prepend_atom (GList * ai, Atom * atom,
AtomCopyDataFunc copy_func, AtomFreeFunc free_func)
{
if (atom)
return g_list_prepend (ai,
build_atom_info_wrapper (atom, copy_func, free_func));
else
return ai;
}
static void
atom_info_list_free (GList * ai)
{
while (ai) {
AtomInfo *info = (AtomInfo *) ai->data;
info->free_func (info->atom);
g_free (info);
ai = g_list_delete_link (ai, ai);
}
}
static AtomData *
atom_data_new (guint32 fourcc)
{
AtomData *data = g_new0 (AtomData, 1);
atom_header_set (&data->header, fourcc, 0, 0);
return data;
}
static void
atom_data_alloc_mem (AtomData * data, guint32 size)
{
if (data->data) {
g_free (data->data);
}
data->data = g_new0 (guint8, size);
data->datalen = size;
}
static AtomData *
atom_data_new_from_gst_buffer (guint32 fourcc, const GstBuffer * buf)
{
AtomData *data = atom_data_new (fourcc);
atom_data_alloc_mem (data, GST_BUFFER_SIZE (buf));
g_memmove (data->data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
return data;
}
static void
atom_data_free (AtomData * data)
{
atom_clear (&data->header);
g_free (data->data);
g_free (data);
}
static void
atom_ftyp_init (AtomFTYP * ftyp, guint32 major, guint32 version, GList * brands)
{
gint index;
GList *it = NULL;
atom_header_set (&ftyp->header, FOURCC_ftyp, 16, 0);
ftyp->major_brand = major;
ftyp->version = version;
/* always include major brand as compatible brand */
ftyp->compatible_brands_size = g_list_length (brands) + 1;
ftyp->compatible_brands = g_new (guint32, ftyp->compatible_brands_size);
ftyp->compatible_brands[0] = major;
index = 1;
for (it = brands; it != NULL; it = g_list_next (it)) {
ftyp->compatible_brands[index++] = GPOINTER_TO_UINT (it->data);
}
}
AtomFTYP *
atom_ftyp_new (AtomsContext * context, guint32 major, guint32 version,
GList * brands)
{
AtomFTYP *ftyp = g_new0 (AtomFTYP, 1);
atom_ftyp_init (ftyp, major, version, brands);
return ftyp;
}
void
atom_ftyp_free (AtomFTYP * ftyp)
{
atom_clear (&ftyp->header);
g_free (ftyp->compatible_brands);
ftyp->compatible_brands = NULL;
g_free (ftyp);
}
static void
atom_esds_init (AtomESDS * esds)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&esds->header, FOURCC_esds, 0, 0, 0, flags);
desc_es_init (&esds->es);
}
static AtomESDS *
atom_esds_new ()
{
AtomESDS *esds = g_new0 (AtomESDS, 1);
atom_esds_init (esds);
return esds;
}
static void
atom_esds_free (AtomESDS * esds)
{
atom_full_clear (&esds->header);
desc_es_descriptor_clear (&esds->es);
g_free (esds);
}
static AtomFRMA *
atom_frma_new ()
{
AtomFRMA *frma = g_new0 (AtomFRMA, 1);
atom_header_set (&frma->header, FOURCC_frma, 0, 0);
return frma;
}
static void
atom_frma_free (AtomFRMA * frma)
{
atom_clear (&frma->header);
g_free (frma);
}
static AtomWAVE *
atom_wave_new ()
{
AtomWAVE *wave = g_new0 (AtomWAVE, 1);
atom_header_set (&wave->header, FOURCC_wave, 0, 0);
return wave;
}
static void
atom_wave_free (AtomWAVE * wave)
{
atom_clear (&wave->header);
atom_info_list_free (wave->extension_atoms);
g_free (wave);
}
static void
atom_sample_entry_init (SampleTableEntry * se, guint32 type)
{
atom_header_set (&se->header, type, 0, 0);
memset (se->reserved, 0, sizeof (guint8) * 6);
se->data_reference_index = 0;
}
static void
atom_sample_entry_free (SampleTableEntry * se)
{
atom_clear (&se->header);
}
static void
sample_entry_mp4a_init (SampleTableEntryMP4A * mp4a)
{
atom_sample_entry_init (&mp4a->se, FOURCC_mp4a);
mp4a->version = 0;
mp4a->revision_level = 0;
mp4a->vendor = 0;
mp4a->channels = 2;
mp4a->sample_size = 16;
mp4a->compression_id = 0;
mp4a->packet_size = 0;
mp4a->sample_rate = 0;
/* following only used if version is 1 */
mp4a->samples_per_packet = 0;
mp4a->bytes_per_packet = 0;
mp4a->bytes_per_frame = 0;
mp4a->bytes_per_sample = 0;
mp4a->extension_atoms = NULL;
}
static SampleTableEntryMP4A *
sample_entry_mp4a_new ()
{
SampleTableEntryMP4A *mp4a = g_new0 (SampleTableEntryMP4A, 1);
sample_entry_mp4a_init (mp4a);
return mp4a;
}
static void
sample_entry_mp4a_free (SampleTableEntryMP4A * mp4a)
{
atom_sample_entry_free (&mp4a->se);
atom_info_list_free (mp4a->extension_atoms);
g_free (mp4a);
}
static void
sample_entry_mp4v_init (SampleTableEntryMP4V * mp4v, AtomsContext * context)
{
atom_sample_entry_init (&mp4v->se, FOURCC_mp4v);
mp4v->version = 0;
mp4v->revision_level = 0;
mp4v->vendor = 0;
mp4v->temporal_quality = 0;
mp4v->spatial_quality = 0;
/* qt and ISO base media do not contradict, and examples agree */
mp4v->horizontal_resolution = 0x00480000;
mp4v->vertical_resolution = 0x00480000;
mp4v->datasize = 0;
mp4v->frame_count = 1;
memset (mp4v->compressor, 0, sizeof (guint8) * 32);
mp4v->depth = 0;
mp4v->color_table_id = 0;
mp4v->extension_atoms = NULL;
}
static void
sample_entry_mp4v_free (SampleTableEntryMP4V * mp4v)
{
atom_sample_entry_free (&mp4v->se);
atom_info_list_free (mp4v->extension_atoms);
g_free (mp4v);
}
static SampleTableEntryMP4V *
sample_entry_mp4v_new (AtomsContext * context)
{
SampleTableEntryMP4V *mp4v = g_new0 (SampleTableEntryMP4V, 1);
sample_entry_mp4v_init (mp4v, context);
return mp4v;
}
static void
atom_stsd_init (AtomSTSD * stsd)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&stsd->header, FOURCC_stsd, 0, 0, 0, flags);
stsd->entries = NULL;
}
static void
atom_stsd_clear (AtomSTSD * stsd)
{
GList *walker;
atom_full_clear (&stsd->header);
walker = stsd->entries;
while (walker) {
GList *aux = walker;
SampleTableEntry *se = (SampleTableEntry *) aux->data;
walker = g_list_next (walker);
stsd->entries = g_list_remove_link (stsd->entries, aux);
switch (se->kind) {
case AUDIO:
sample_entry_mp4a_free ((SampleTableEntryMP4A *) se);
break;
case VIDEO:
sample_entry_mp4v_free ((SampleTableEntryMP4V *) se);
break;
default:
/* best possible cleanup */
atom_sample_entry_free (se);
}
g_list_free (aux);
}
}
static void
atom_ctts_init (AtomCTTS * ctts)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&ctts->header, FOURCC_ctts, 0, 0, 0, flags);
ctts->entries = NULL;
}
static AtomCTTS *
atom_ctts_new ()
{
AtomCTTS *ctts = g_new0 (AtomCTTS, 1);
atom_ctts_init (ctts);
return ctts;
}
static void
atom_ctts_free (AtomCTTS * ctts)
{
GList *walker;
atom_full_clear (&ctts->header);
walker = ctts->entries;
while (walker) {
GList *aux = walker;
walker = g_list_next (walker);
ctts->entries = g_list_remove_link (ctts->entries, aux);
g_free ((CTTSEntry *) aux->data);
g_list_free (aux);
}
g_free (ctts);
}
static void
atom_stts_init (AtomSTTS * stts)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&stts->header, FOURCC_stts, 0, 0, 0, flags);
stts->entries = NULL;
}
static void
atom_stts_clear (AtomSTTS * stts)
{
GList *walker;
atom_full_clear (&stts->header);
walker = stts->entries;
while (walker) {
GList *aux = walker;
walker = g_list_next (walker);
stts->entries = g_list_remove_link (stts->entries, aux);
g_free ((STTSEntry *) aux->data);
g_list_free (aux);
}
stts->n_entries = 0;
}
static void
atom_stsz_init (AtomSTSZ * stsz)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&stsz->header, FOURCC_stsz, 0, 0, 0, flags);
stsz->sample_size = 0;
stsz->table_size = 0;
stsz->entries = NULL;
}
static void
atom_stsz_clear (AtomSTSZ * stsz)
{
atom_full_clear (&stsz->header);
g_list_free (stsz->entries);
stsz->entries = NULL;
stsz->table_size = 0;
}
static void
atom_stsc_init (AtomSTSC * stsc)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&stsc->header, FOURCC_stsc, 0, 0, 0, flags);
stsc->entries = NULL;
stsc->n_entries = 0;
}
static void
atom_stsc_clear (AtomSTSC * stsc)
{
GList *walker;
atom_full_clear (&stsc->header);
walker = stsc->entries;
while (walker) {
GList *aux = walker;
walker = g_list_next (walker);
stsc->entries = g_list_remove_link (stsc->entries, aux);
g_free ((STSCEntry *) aux->data);
g_list_free (aux);
}
stsc->n_entries = 0;
}
static void
atom_co64_init (AtomSTCO64 * co64)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&co64->header, FOURCC_co64, 0, 0, 0, flags);
co64->entries = NULL;
co64->n_entries = 0;
}
static void
atom_stco64_clear (AtomSTCO64 * stco64)
{
GList *walker;
atom_full_clear (&stco64->header);
walker = stco64->entries;
while (walker) {
GList *aux = walker;
walker = g_list_next (walker);
stco64->entries = g_list_remove_link (stco64->entries, aux);
g_free ((guint64 *) aux->data);
g_list_free (aux);
}
stco64->n_entries = 0;
}
static void
atom_stss_init (AtomSTSS * stss)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&stss->header, FOURCC_stss, 0, 0, 0, flags);
stss->entries = NULL;
stss->n_entries = 0;
}
static void
atom_stss_clear (AtomSTSS * stss)
{
atom_full_clear (&stss->header);
g_list_free (stss->entries);
stss->entries = NULL;
stss->n_entries = 0;
}
static void
atom_stbl_init (AtomSTBL * stbl)
{
atom_header_set (&stbl->header, FOURCC_stbl, 0, 0);
atom_stts_init (&stbl->stts);
atom_stss_init (&stbl->stss);
atom_stsd_init (&stbl->stsd);
atom_stsz_init (&stbl->stsz);
atom_stsc_init (&stbl->stsc);
stbl->ctts = NULL;
atom_co64_init (&stbl->stco64);
}
static void
atom_stbl_clear (AtomSTBL * stbl)
{
atom_clear (&stbl->header);
atom_stsd_clear (&stbl->stsd);
atom_stts_clear (&stbl->stts);
atom_stss_clear (&stbl->stss);
atom_stsc_clear (&stbl->stsc);
atom_stsz_clear (&stbl->stsz);
if (stbl->ctts) {
atom_ctts_free (stbl->ctts);
}
atom_stco64_clear (&stbl->stco64);
}
static void
atom_vmhd_init (AtomVMHD * vmhd, AtomsContext * context)
{
guint8 flags[3] = { 0, 0, 1 };
atom_full_init (&vmhd->header, FOURCC_vmhd, 0, 0, 0, flags);
vmhd->graphics_mode = 0x0;
memset (vmhd->opcolor, 0, sizeof (guint16) * 3);
if (context->flavor == ATOMS_TREE_FLAVOR_MOV) {
vmhd->graphics_mode = 0x40;
vmhd->opcolor[0] = 32768;
vmhd->opcolor[1] = 32768;
vmhd->opcolor[2] = 32768;
}
}
static AtomVMHD *
atom_vmhd_new (AtomsContext * context)
{
AtomVMHD *vmhd = g_new0 (AtomVMHD, 1);
atom_vmhd_init (vmhd, context);
return vmhd;
}
static void
atom_vmhd_free (AtomVMHD * vmhd)
{
atom_full_clear (&vmhd->header);
g_free (vmhd);
}
static void
atom_smhd_init (AtomSMHD * smhd)
{
guint8 flags[3] = { 0, 0, 0 };
atom_full_init (&smhd->header, FOURCC_smhd, 0, 0, 0, flags);
smhd->balance = 0;
smhd->reserved = 0;
}
static AtomSMHD *
atom_smhd_new ()