Move 'extern C' to the beginning of libmkv.h
[libmkv.git] / src / tracks.c
blobab612253101daa507a7e14d243ed9bd675203345
1 /*****************************************************************************
2 * tracks.c:
3 *****************************************************************************
4 * Copyright (C) 2007 libmkv
5 * $Id: $
7 * Authors: Mike Matsnev
8 * Nathan Caldwell
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
24 #include "config.h"
25 #include "libmkv.h"
26 #include "matroska.h"
28 /* TODO: Figure out what can actually fail without damaging the track. */
30 #define TRACK_STEP 4
32 mk_Track *mk_createTrack(mk_Writer *w, mk_TrackConfig *tc)
34 mk_Context *ti, *v;
35 int i;
36 mk_Track *track = calloc(1, sizeof(*track));
37 if (track == NULL)
38 return NULL;
40 if (w->num_tracks + 1 > w->alloc_tracks)
42 if ((w->tracks_arr = realloc(w->tracks_arr, (w->alloc_tracks + TRACK_STEP) * sizeof(mk_Track *))) == NULL)
43 return NULL; // FIXME
44 w->alloc_tracks += TRACK_STEP;
46 w->tracks_arr[w->num_tracks] = track;
47 track->track_id = ++w->num_tracks;
49 if (w->tracks == NULL)
51 if ((w->tracks = mk_createContext(w, w->root, MATROSKA_ID_TRACKS)) == NULL) // tracks
52 return NULL;
55 if ((ti = mk_createContext(w, w->tracks, MATROSKA_ID_TRACKENTRY)) == NULL) // TrackEntry
56 return NULL;
57 if (mk_writeUInt(ti, MATROSKA_ID_TRACKNUMBER, track->track_id) < 0) // TrackNumber
58 return NULL;
59 if (tc->trackUID) {
60 if (mk_writeUInt(ti, MATROSKA_ID_TRACKUID, tc->trackUID) < 0) /* TrackUID */
61 return NULL;
62 } else {
64 * If we aren't given a UID, randomly generate one.
65 * NOTE: It would probably be better to CRC32 some unique track information
66 * in place of something completely random.
68 unsigned long track_uid;
69 track_uid = random();
71 if (mk_writeUInt(ti, MATROSKA_ID_TRACKUID, track_uid) < 0) /* TrackUID */
72 return NULL;
74 if (mk_writeUInt(ti, MATROSKA_ID_TRACKTYPE, tc->trackType) < 0) // TrackType
75 return NULL;
76 track->track_type = tc->trackType;
77 if (mk_writeUInt(ti, MATROSKA_ID_TRACKFLAGLACING, tc->flagLacing) < 0) // FlagLacing
78 return NULL;
79 if (mk_writeStr(ti, MATROSKA_ID_CODECID, tc->codecID) < 0) // CodecID
80 return NULL;
81 if (tc->codecPrivateSize && (tc->codecPrivate != NULL))
82 if (mk_writeBin(ti, MATROSKA_ID_CODECPRIVATE, tc->codecPrivate, tc->codecPrivateSize) < 0) // CodecPrivate
83 return NULL;
84 if (tc->defaultDuration) {
85 if (mk_writeUInt(ti, MATROSKA_ID_TRACKDEFAULTDURATION, tc->defaultDuration) < 0)
86 return NULL;
87 track->default_duration = tc->defaultDuration;
89 if (tc->language)
90 if (mk_writeStr(ti, MATROSKA_ID_TRACKLANGUAGE, tc->language) < 0) // Language
91 return NULL;
92 if (tc->flagEnabled != 1)
93 if (mk_writeUInt(ti, MATROSKA_ID_TRACKFLAGENABLED, tc->flagEnabled) < 0) // FlagEnabled
94 return NULL;
95 if (mk_writeUInt(ti, MATROSKA_ID_TRACKFLAGDEFAULT, tc->flagDefault) < 0) // FlagDefault
96 return NULL;
97 if (tc->flagForced)
98 if (mk_writeUInt(ti, MATROSKA_ID_TRACKFLAGFORCED, tc->flagForced) < 0) // FlagForced
99 return NULL;
100 if (tc->minCache)
101 if (mk_writeUInt(ti, MATROSKA_ID_TRACKMINCACHE, tc->minCache) < 0) // MinCache
102 return NULL;
103 /* FIXME: this won't handle NULL values, which signals that the cache is disabled. */
104 if (tc->maxCache)
105 if (mk_writeUInt(ti, MATROSKA_ID_TRACKMAXCACHE, tc->maxCache) < 0) // MaxCache
106 return NULL;
108 switch (tc->trackType)
110 case MK_TRACK_VIDEO: // Video
111 if ((v = mk_createContext(w, ti, MATROSKA_ID_TRACKVIDEO)) == NULL)
112 return NULL;
113 if (tc->extra.video.pixelCrop[0] != 0 || tc->extra.video.pixelCrop[1] != 0 || tc->extra.video.pixelCrop[2] != 0 || tc->extra.video.pixelCrop[3] != 0) {
114 for (i = 0; i < 4; i++) {
115 /* Each pixel crop ID is 0x11 away from the next.
116 * In order from 0x54AA to 0x54DD they are bottom, top, left, right.
118 if (mk_writeUInt(v, MATROSKA_ID_VIDEOPIXELCROPBOTTOM + (i * 0x11), tc->extra.video.pixelCrop[i]) < 0) // PixelCrop
119 return NULL;
122 if (mk_writeUInt(v, MATROSKA_ID_VIDEOPIXELWIDTH, tc->extra.video.pixelWidth) < 0) // PixelWidth
123 return NULL;
124 if (mk_writeUInt(v, MATROSKA_ID_VIDEOPIXELHEIGHT, tc->extra.video.pixelHeight) < 0 ) // PixelHeight
125 return NULL;
126 if (mk_writeUInt(v, MATROSKA_ID_VIDEODISPLAYWIDTH, tc->extra.video.displayWidth) < 0) // DisplayWidth
127 return NULL;
128 if (mk_writeUInt(v, MATROSKA_ID_VIDEODISPLAYHEIGHT, tc->extra.video.displayHeight) < 0) // DisplayHeight
129 return NULL;
130 if (tc->extra.video.displayUnit)
131 if (mk_writeUInt(v, MATROSKA_ID_VIDEODISPLAYUNIT, tc->extra.video.displayUnit) < 0) // DisplayUnit
132 return NULL;
133 break;
134 case MK_TRACK_AUDIO: // Audio
135 if ((v = mk_createContext(w, ti, MATROSKA_ID_TRACKAUDIO)) == NULL)
136 return NULL;
137 if (mk_writeFloat(v, MATROSKA_ID_AUDIOSAMPLINGFREQ, tc->extra.audio.samplingFreq) < 0) // SamplingFrequency
138 return NULL;
139 if (mk_writeUInt(v, MATROSKA_ID_AUDIOCHANNELS, tc->extra.audio.channels) < 0) // Channels
140 return NULL;
141 if (tc->extra.audio.bitDepth)
142 if (mk_writeUInt(v, MATROSKA_ID_AUDIOBITDEPTH, tc->extra.audio.bitDepth) < 0) // BitDepth
143 return NULL;
144 break;
145 default: // Other TODO: Implement other track types.
146 return NULL;
149 if (mk_closeContext(v, 0) < 0)
150 return NULL;
151 if (mk_closeContext(ti, 0) < 0)
152 return NULL;
154 return track;
157 int mk_writeTracks(mk_Writer *w, mk_Context *tracks)
159 w->seek_data.tracks = w->root->d_cur;
161 CHECK(mk_closeContext(w->tracks, 0));
163 return 0;