Example #1
0
static int mk_closeCluster(mk_Writer *w) {
  if (w->cluster == NULL)
    return 0;
  CHECK(mk_closeContext(w->cluster, 0));
  w->cluster = NULL;
  CHECK(mk_flushContextData(w->root));
  return 0;
}
Example #2
0
int	  mk_close(mk_Writer *w) {
  int	ret = 0;
  if (mk_flushFrame(w) < 0 || mk_closeCluster(w) < 0)
    ret = -1;
  if (w->wrote_header) {
    fseek(w->fp, w->duration_ptr, SEEK_SET);
    if (mk_writeFloatRaw(w->root, (float)((double)(w->max_frame_tc+w->def_duration) / w->timescale)) < 0 ||
	mk_flushContextData(w->root) < 0)
      ret = -1;
  }
  mk_destroyContexts(w);
  fclose(w->fp);
  free(w);
  return ret;
}
Example #3
0
static int	  mk_closeContext(mk_Context *c, unsigned *off) {
  if (c->id) {
    CHECK(mk_writeID(c->parent, c->id));
    CHECK(mk_writeSize(c->parent, c->d_cur));
  }

  if (c->parent && off != NULL)
    *off += c->parent->d_cur;

  CHECK(mk_flushContextData(c));

  if (c->next)
    c->next->prev = c->prev;
  *(c->prev) = c->next;
  c->next = c->owner->freelist;
  c->owner->freelist = c;

  return 0;
}
Example #4
0
int mk_close(mk_Writer *w)
{
	int i, ret = 0;
	mk_Track *tk;
	int64_t max_frame_tc = w->tracks_arr[0]->max_frame_tc;
	uint64_t segment_size = 0;
	unsigned char c_size[8];
	unsigned char segment_uid[16];

	md5_finish(&w->segment_md5, segment_uid);

	for (i = w->num_tracks - 1; i >= 0; i--) {
		tk = w->tracks_arr[i];
		if (mk_flushFrame(w, tk) < 0)
			ret = -1;
	}

	if (mk_closeCluster(w) < 0)
		ret = -1;

	w->seek_data.cues = w->f_pos - w->segment_ptr;
	if (mk_closeContext(w->cues, 0) < 0)
		ret = -1;
	if (mk_flushContextData(w->root) < 0)
		ret = -1;

	if (w->cluster.seekhead) {
		w->seek_data.seekhead = w->f_pos - w->segment_ptr;
		if (mk_closeContext(w->cluster.seekhead, 0) < 0)
			ret = -1;
		if (mk_flushContextData(w->root) < 0)
			ret = -1;
	}

	if (w->attachments != NULL) {
		w->seek_data.attachments = w->f_pos - w->segment_ptr;
		mk_writeAttachments(w);
		if (mk_flushContextData(w->root) < 0)
			ret = -1;
	}

	if (w->tags != NULL) {
		w->seek_data.tags = w->f_pos - w->segment_ptr;
		mk_writeTags(w);
		if (mk_flushContextData(w->root) < 0)
			ret = -1;
	}

	if (w->chapters != NULL) {
		if (w->vlc_compat) {
			if (mk_flushContextData(w->root) < 0)
				ret = -1;
			if (mk_seekFile(w, w->segment_ptr + RESERVED_SEEKHEAD + 3) < 0)
				ret = -1;
		}
		w->seek_data.chapters = w->f_pos - w->segment_ptr;
		mk_writeChapters(w);
		if (mk_flushContextData(w->root) < 0)
			ret = -1;
		if (w->vlc_compat) {
			if (mk_writeVoid(w->root, (RESERVED_CHAPTERS - (w->f_pos - w->segment_ptr - RESERVED_SEEKHEAD - 3))) < 0)
				ret = -1;
			if (mk_flushContextData(w->root) < 0)
				ret = -1;
		}
	}

	if (w->wrote_header) {
		if (w->vlc_compat) {
			if (mk_seekFile(w, w->segment_ptr) < 0)
				ret = -1;
		}

		if (mk_writeSeekHead(w, &w->seek_data.seekhead) < 0)
			ret = -1;
		w->seek_data.seekhead -= w->segment_ptr;

		if (w->vlc_compat) {
			if (mk_flushContextData(w->root) < 0)
				ret = -1;
			if (mk_writeVoid(w->root, (RESERVED_SEEKHEAD - (w->f_pos - w->segment_ptr))) < 0)
				ret = -1;
		}

		if (mk_flushContextData(w->root) < 0)
			ret = -1;

		if (!w->vlc_compat) {
			int i = w->seek_data.segmentinfo;
			w->seek_data.segmentinfo = 0;
			w->seek_data.tracks = 0;
			w->seek_data.cues = 0;
			w->seek_data.chapters = 0;
			w->seek_data.attachments = 0;
			w->seek_data.tags = 0;
			if (mk_seekFile(w, w->segment_ptr) < 0)
				ret = -1;
			if (mk_writeSeekHead(w, NULL) < 0 || mk_flushContextData(w->root) < 0)
				ret = -1;
			// The conditional below is easier to understand, but incorrect
			// because f_pos is unsigned and causes the lhs to be evaluated
			// as an unsigned quantity.
			// if (((i + w->segment_ptr) - w->f_pos - 2) > 1)
			if ((i + w->segment_ptr) > (w->f_pos + 3))
				if (mk_writeVoid(w->root, (i + w->segment_ptr) - w->f_pos - 2) < 0
					|| mk_flushContextData(w->root) < 0)
					ret = -1;
		}

		if (mk_seekFile(w, w->duration_ptr) < 0)
			ret = -1;
		if (mk_writeFloatRaw(w->root,
							 (float) ((double) (max_frame_tc + w->def_duration) /
							 w->timescale)) < 0
			|| mk_flushContextData(w->root) < 0)
			ret = -1;
		if (mk_seekFile(w, w->segment_ptr - 8) < 0)
			ret = -1;
		segment_size = w->f_eof - w->segment_ptr;
		for (i = 7; i > 0; --i)
			c_size[i] = segment_size >> (8 * (7 - i));
		c_size[i] = 0x01;
		if (mk_appendContextData(w->root, &c_size, 8) < 0 ||
			mk_flushContextData(w->root) < 0)
			ret = -1;
		if (mk_seekFile(w, w->segmentuid_ptr) < 0)
			ret = -1;
		if (mk_writeBin(w->root, MATROSKA_ID_SEGMENTUID, segment_uid,
						sizeof(segment_uid)) < 0 ||
			mk_flushContextData(w->root) < 0)
			ret = -1;
	}

    /* update any track private data that may have changed */
	for (i = w->num_tracks - 1; i >= 0; i--) {
		tk = w->tracks_arr[i];
		if (tk->private_data_size && tk->private_data)
		{
			if (mk_seekFile(w, tk->private_data_ptr) < 0)
				ret = -1;
			if (mk_writeBin(w->root, MATROSKA_ID_CODECPRIVATE,
							tk->private_data, tk->private_data_size) < 0 ||
				mk_flushContextData(w->root) < 0)
				ret = -1;
			free(tk->private_data);
        }
		w->tracks_arr[i] = NULL;
		--w->num_tracks;
		free(tk);
	}

	if (mk_closeContext(w->root, 0) < 0)
		ret = -1;
	mk_destroyContexts(w);
	fclose(w->fp);
	free(w->tracks_arr);
	free(w);

	return ret;
}
Example #5
0
int mk_writeHeader(mk_Writer *w, const char *writingApp)
{
	mk_Context *c;
	mk_Track *tk;
	int i;
	int64_t offset = 0;

	if (w->wrote_header)
		return -1;

	md5_starts(&w->segment_md5);	/* Initalize MD5 */

	CHECK(mk_writeEbmlHeader(w, "matroska", MATROSKA_VERSION, MATROSKA_VERSION));

	/* Segment */
	if ((c = mk_createContext(w, w->root, MATROSKA_ID_SEGMENT)) == NULL)
		return -1;
	CHECK(mk_flushContextID(c));
	w->segment_ptr = c->d_cur;
	CHECK(mk_closeContext(c, &w->segment_ptr));

	if (w->vlc_compat) {
		CHECK(mk_writeVoid(w->root, RESERVED_SEEKHEAD));	/* Reserved space for SeekHead */
		CHECK(mk_writeVoid(w->root, RESERVED_CHAPTERS));	/* Reserved space for Chapters */
	} else {
		w->seek_data.seekhead = 0x80000000;
		CHECK(mk_writeSeekHead(w, &w->seekhead_ptr));
		w->seek_data.seekhead = 0;
	}

	if ((c = mk_createContext(w, w->root, MATROSKA_ID_INFO)) == NULL)	/* SegmentInfo */
		return -1;
	w->seek_data.segmentinfo = w->root->d_cur - w->segment_ptr;
	/* Reserve space for a SegmentUID (16 bytes + 1 byte longer EBML ID), to be written it later. */
	CHECK(mk_writeVoid(c, 16 + 1));
	CHECK(mk_writeStr(c, MATROSKA_ID_MUXINGAPP, PACKAGE_STRING));	/* MuxingApp */
	CHECK(mk_writeStr(c, MATROSKA_ID_WRITINGAPP, writingApp));	/* WritingApp */
	CHECK(mk_writeUInt(c, MATROSKA_ID_TIMECODESCALE, w->timescale));	/* TimecodeScale */
	CHECK(mk_writeFloat(c, MATROSKA_ID_DURATION, 0));	/* Duration */
	w->duration_ptr = c->d_cur - 4;
	CHECK(mk_closeContext(c, &offset));
	w->duration_ptr += offset;
	w->segmentuid_ptr = offset;

	w->seek_data.tracks = w->root->d_cur - w->segment_ptr;

	if (w->tracks) {
		offset = 0;
		CHECK(mk_closeContext(w->tracks, &offset));
		for (i = 0; i < w->num_tracks; i++) {
			tk = w->tracks_arr[i];
			if (tk->private_data_size)
				tk->private_data_ptr += offset;
		}
	}

	CHECK(mk_flushContextData(w->root));

	w->wrote_header = 1;
	w->def_duration = w->tracks_arr[0]->default_duration;
	return 0;
}
Example #6
0
int	  mk_writeHeader(mk_Writer *w, const char *writingApp,
			 const char *codecID,
			 const void *codecPrivate, unsigned codecPrivateSize,
			 int64_t default_frame_duration,
			 int64_t timescale,
			 unsigned width, unsigned height,
			 unsigned d_width, unsigned d_height)
{
  mk_Context  *c, *ti, *v;

  if (w->wrote_header)
    return -1;

  w->timescale = timescale;
  w->def_duration = default_frame_duration;

  if ((c = mk_createContext(w, w->root, 0x1a45dfa3)) == NULL) // EBML
    return -1;
  CHECK(mk_writeUInt(c, 0x4286, 1)); // EBMLVersion
  CHECK(mk_writeUInt(c, 0x42f7, 1)); // EBMLReadVersion
  CHECK(mk_writeUInt(c, 0x42f2, 4)); // EBMLMaxIDLength
  CHECK(mk_writeUInt(c, 0x42f3, 8)); // EBMLMaxSizeLength
  CHECK(mk_writeStr(c, 0x4282, "matroska")); // DocType
  CHECK(mk_writeUInt(c, 0x4287, 1)); // DocTypeVersion
  CHECK(mk_writeUInt(c, 0x4285, 1)); // DocTypeReadversion
  CHECK(mk_closeContext(c, 0));

  if ((c = mk_createContext(w, w->root, 0x18538067)) == NULL) // Segment
    return -1;
  CHECK(mk_flushContextID(c));
  CHECK(mk_closeContext(c, 0));

  if ((c = mk_createContext(w, w->root, 0x1549a966)) == NULL) // SegmentInfo
    return -1;
  CHECK(mk_writeStr(c, 0x4d80, "Haali Matroska Writer b0"));
  CHECK(mk_writeStr(c, 0x5741, writingApp));
  CHECK(mk_writeUInt(c, 0x2ad7b1, w->timescale));
  CHECK(mk_writeFloat(c, 0x4489, 0));
  w->duration_ptr = c->d_cur - 4;
  CHECK(mk_closeContext(c, &w->duration_ptr));

  if ((c = mk_createContext(w, w->root, 0x1654ae6b)) == NULL) // tracks
    return -1;
  if ((ti = mk_createContext(w, c, 0xae)) == NULL) // TrackEntry
    return -1;
  CHECK(mk_writeUInt(ti, 0xd7, 1)); // TrackNumber
  CHECK(mk_writeUInt(ti, 0x73c5, 1)); // TrackUID
  CHECK(mk_writeUInt(ti, 0x83, 1)); // TrackType
  CHECK(mk_writeUInt(ti, 0x9c, 0)); // FlagLacing
  CHECK(mk_writeStr(ti, 0x86, codecID)); // CodecID
  if (codecPrivateSize)
    CHECK(mk_writeBin(ti, 0x63a2, codecPrivate, codecPrivateSize)); // CodecPrivate
  if (default_frame_duration)
    CHECK(mk_writeUInt(ti, 0x23e383, default_frame_duration)); // DefaultDuration

  if ((v = mk_createContext(w, ti, 0xe0)) == NULL) // Video
    return -1;
  CHECK(mk_writeUInt(v, 0xb0, width));
  CHECK(mk_writeUInt(v, 0xba, height));
  CHECK(mk_writeUInt(v, 0x54b0, d_width));
  CHECK(mk_writeUInt(v, 0x54ba, d_height));
  CHECK(mk_closeContext(v, 0));

  CHECK(mk_closeContext(ti, 0));

  CHECK(mk_closeContext(c, 0));

  CHECK(mk_flushContextData(w->root));

  w->wrote_header = 1;

  return 0;
}