コード例 #1
0
ファイル: matroska.c プロジェクト: wmertens/libmkv
int mk_writeSeek(mk_Writer *w, mk_Context *c, unsigned seek_id,
				 uint64_t seek_pos)
{
	mk_Context *s;

	if ((s = mk_createContext(w, c, MATROSKA_ID_SEEKENTRY)) == NULL)	/* Seek */
		return -1;
	CHECK(mk_writeUInt(s, MATROSKA_ID_SEEKID, seek_id));	/* SeekID */
	CHECK(mk_writeUInt(s, MATROSKA_ID_SEEKPOSITION, seek_pos));	/* SeekPosition */
	CHECK(mk_closeContext(s, 0));

	return 0;
}
コード例 #2
0
ファイル: matroska.c プロジェクト: hiccupzhu/misc_starting
int	  mk_flushFrame(mk_Writer *w) {
  int64_t	delta, ref = 0;
  unsigned	fsize, bgsize;
  unsigned char	c_delta_flags[3];

  if (!w->in_frame)
    return 0;

  delta = w->frame_tc/w->timescale - w->cluster_tc_scaled;
  //if (delta > 32767ll || delta < -32768ll)
  if (delta > 32767I64 || delta < -32768I64) //lsp051226
    CHECK(mk_closeCluster(w));

  if (w->cluster == NULL) {
    w->cluster_tc_scaled = w->frame_tc / w->timescale;
    w->cluster = mk_createContext(w, w->root, 0x1f43b675); // Cluster
    if (w->cluster == NULL)
      return -1;

    CHECK(mk_writeUInt(w->cluster, 0xe7, w->cluster_tc_scaled)); // Timecode

    delta = 0;
  }

  fsize = w->frame ? w->frame->d_cur : 0;
  bgsize = fsize + 4 + mk_ebmlSizeSize(fsize + 4) + 1;
  if (!w->keyframe) {
    ref = w->prev_frame_tc_scaled - w->cluster_tc_scaled - delta;
    bgsize += 1 + 1 + mk_ebmlSIntSize(ref);
  }

  CHECK(mk_writeID(w->cluster, 0xa0)); // BlockGroup
  CHECK(mk_writeSize(w->cluster, bgsize));
  CHECK(mk_writeID(w->cluster, 0xa1)); // Block
  CHECK(mk_writeSize(w->cluster, fsize + 4));
  CHECK(mk_writeSize(w->cluster, 1)); // track number

  c_delta_flags[0] = delta >> 8;
  c_delta_flags[1] = delta;
  c_delta_flags[2] = 0;
  CHECK(mk_appendContextData(w->cluster, c_delta_flags, 3));
  if (w->frame) {
    CHECK(mk_appendContextData(w->cluster, w->frame->data, w->frame->d_cur));
    w->frame->d_cur = 0;
  }
  if (!w->keyframe)
    CHECK(mk_writeSInt(w->cluster, 0xfb, ref)); // ReferenceBlock

  w->in_frame = 0;
  w->prev_frame_tc_scaled = w->cluster_tc_scaled + delta;

  if (w->cluster->d_cur > CLSIZE)
    CHECK(mk_closeCluster(w));

  return 0;
}
コード例 #3
0
ファイル: chapters.c プロジェクト: VladimirTyrin/libmkv
int mk_createChapterSimple(mk_Writer *w, uint64_t start, uint64_t end,
						   char *name)
{
	mk_Context *ca, *cd;
	unsigned long chapter_uid;

	/*
	 * Generate a random UID for this Chapter.
	 * NOTE: This probably should be a CRC32 of some unique chapter information.
	 *        In place of being completely random.
	 */
	chapter_uid = random();

	if (w->chapters == NULL) {
		unsigned long edition_uid;
		edition_uid = random();

		/* Chapters */
		if ((w->chapters = mk_createContext(w, w->root, MATROSKA_ID_CHAPTERS)) == NULL)
			return -1;
		/* EditionEntry */
		if ((w->edition_entry = mk_createContext(w, w->chapters, MATROSKA_ID_EDITIONENTRY)) == NULL)
			return -1;
		/* EditionUID - See note above about Chapter UID. */
		CHECK(mk_writeUInt(w->edition_entry, MATROSKA_ID_EDITIONUID, edition_uid));
		/* EditionFlagDefault - This is set to 1 to force this Edition to be the default one. */
		CHECK(mk_writeUInt(w->edition_entry, MATROSKA_ID_EDITIONFLAGDEFAULT, 1));
		/* EditionFlagOrdered - Force simple chapters. */
		CHECK(mk_writeUInt(w->edition_entry, MATROSKA_ID_EDITIONFLAGORDERED, 0));
	}
	/* ChapterAtom */
	if ((ca = mk_createContext(w, w->edition_entry, MATROSKA_ID_CHAPTERATOM)) == NULL)
		return -1;
	CHECK(mk_writeUInt(ca, MATROSKA_ID_CHAPTERUID, chapter_uid));	/* ChapterUID */
	CHECK(mk_writeUInt(ca, MATROSKA_ID_CHAPTERTIMESTART, start));	/* ChapterTimeStart */
	if (end != start)			/* Only create a StartTime if chapter length would be 0. */
		CHECK(mk_writeUInt(ca, MATROSKA_ID_CHAPTERTIMEEND, end));	/* ChapterTimeEnd */
	if (name != NULL) {
		/* ChapterDisplay */
		if ((cd = mk_createContext(w, ca, MATROSKA_ID_CHAPTERDISPLAY)) == NULL)
			return -1;
		CHECK(mk_writeStr(cd, MATROSKA_ID_CHAPTERSTRING, name));	/* ChapterString */
		CHECK(mk_closeContext(cd, 0));
	}
	CHECK(mk_closeContext(ca, 0));

	return 0;
}
コード例 #4
0
ファイル: matroska.c プロジェクト: wmertens/libmkv
int mk_flushFrame(mk_Writer *w, mk_Track *track)
{
	mk_Context *c, *tp;
	int64_t delta, ref = 0;
	unsigned fsize, bgsize;
	uint8_t flags, c_delta[2];
	int i;
	char *laced = NULL;
	uint64_t length = 0;
	uint64_t block_duration = 0;

	if (!track->in_frame)
		return 0;

	delta = track->frame.timecode / w->timescale - w->cluster.tc_scaled;
	block_duration = track->frame.duration / w->timescale;

	/* NOTE: If we switch rapidly back-and-forth between tracks with
	 * drastically different timecodes this causes a new cluster to
	 * be written each time a switch is made. This causes unnecessary
	 * overhead. The calling application is assumed to have interleaved
	 * track samples based on timestamp.
	 */

	/* Soft limit: If the frame is a video keyframe and we are not closer than
	 * 2 seconds to the last cluster, start a new cluster.
	 */
	if (track->track_type == MK_TRACK_VIDEO && track->frame.keyframe && delta > 2000ll)
		CHECK(mk_closeCluster(w));

	/* Hard limit: if the current cluster is greater than 20 seconds,
	 * start a new cluster
	 */
	if (delta > 20000ll || delta < -20000ll)
		CHECK(mk_closeCluster(w));

	if (w->cluster.context == NULL) {
		w->cluster.tc_scaled = track->frame.timecode / w->timescale;
		/* Cluster */
		w->cluster.context = mk_createContext(w, w->root, MATROSKA_ID_CLUSTER);
		if (w->cluster.context == NULL)
			return -1;

		w->cluster.pointer = w->f_pos - w->segment_ptr;

		/* Cluster SeekEntry */
		CHECK(mk_writeSeek(w, w->cluster.seekhead, MATROSKA_ID_CLUSTER,
						   w->cluster.pointer));

		/* Cluster Timecode */
		CHECK(mk_writeUInt(w->cluster.context, MATROSKA_ID_CLUSTERTIMECODE, w->cluster.tc_scaled));

		delta = 0;
		w->cluster.block_count = 0;
	}

	/* Calculate the encoded lacing sizes. */
	switch (track->frame.lacing) {
		case MK_LACING_XIPH:
			laced =	mk_laceXiph(track->frame.lacing_sizes,
								track->frame.lacing_num_frames, &length);
			break;
		case MK_LACING_EBML:
		{
			uint64_t u_size = 0;
			/* Add one below for the frame count. */
			length += mk_ebmlSizeSize(track->frame.lacing_sizes[0]) + 1;
			for (i = 1; i < track->frame.lacing_num_frames; i++) {
				u_size = llabs(track->frame.lacing_sizes[i] -
							   track->frame.lacing_sizes[i - 1]);
				/* Shift by one so we get the right size for a signed number. */
				length += mk_ebmlSizeSize((u_size) << 1);
			}
			break;
		}
		case MK_LACING_FIXED:
		{
			laced = calloc(1, sizeof(*laced));
			laced[0] = track->frame.lacing_num_frames;
			++length;
			break;
		}
		default:
			break;
	}

	fsize = track->frame.data ? track->frame.data->d_cur : 0;
	bgsize = fsize + 4 + mk_ebmlSizeSize(fsize + 4 + length) + 1 + length;
	if (!track->frame.keyframe) {
		ref = track->prev_frame_tc_scaled - w->cluster.tc_scaled - delta;
		bgsize += 1 + 1 + mk_ebmlSIntSize(ref);
	}
	if (block_duration > 0)	/* BlockDuration */
	{
		bgsize += 1 + 1 + mk_ebmlUIntSize(block_duration);
	}

	CHECK(mk_writeID(w->cluster.context, MATROSKA_ID_BLOCKGROUP));	/* BlockGroup */
	CHECK(mk_writeSize(w->cluster.context, bgsize));
	CHECK(mk_writeID(w->cluster.context, MATROSKA_ID_BLOCK));	/* Block */
	CHECK(mk_writeSize(w->cluster.context, fsize + 4 + length));	/* BlockSize */
	CHECK(mk_writeSize(w->cluster.context, track->track_id));	/* track number */

	w->cluster.block_count++;

	c_delta[0] = delta >> 8;
	c_delta[1] = delta;
	/* Timecode relative to Cluster. */
	CHECK(mk_appendContextData(w->cluster.context, c_delta, 2));

/*	flags = ( track->frame.keyframe << 8 ) | track->frame.lacing; */
	flags = track->frame.lacing << 1;	/* Flags: Bit 5-6 describe what type of lacing to use. */
	CHECK(mk_appendContextData(w->cluster.context, &flags, 1));
	if (track->frame.lacing) {
		if (track->frame.lacing == MK_LACING_EBML) {
			/* Number of frames in lace - 1 */
			CHECK(mk_appendContextData(w->cluster.context, &track->frame.lacing_num_frames, 1));
			/* Size of 1st frame. */
			CHECK(mk_writeSize(w->cluster.context, track->frame.lacing_sizes[0]));
			for (i = 1; i < track->frame.lacing_num_frames; i++) {
				/* Size difference between previous size and this size. */
				CHECK(mk_writeSSize(w->cluster.context, track->frame.lacing_sizes[i] - track->frame.lacing_sizes[i - 1]));
			}
		} else if (length > 0 && laced != NULL) {
			CHECK(mk_appendContextData(w->cluster.context, laced, length));
			free(laced);
			laced = NULL;
		}
	}

	if (track->frame.data) {
		CHECK(mk_appendContextData(w->cluster.context, track->frame.data->data,
								   track->frame.data->d_cur));
		track->frame.data->d_cur = 0;
	}
	if (!track->frame.keyframe)		/* ReferenceBlock */
		CHECK(mk_writeSInt(w->cluster.context, MATROSKA_ID_REFERENCEBLOCK, ref));

	if (block_duration > 0)	/* BlockDuration */
		CHECK(mk_writeUInt(w->cluster.context, 0x9b, block_duration));

	/* This may get a little out of hand, but it seems sane enough for now. */
	if (track->frame.keyframe && (track->track_type == MK_TRACK_VIDEO)) {
/*	if (track->frame.keyframe && (track->track_type & MK_TRACK_VIDEO) && ((track->prev_cue_pos + 3*CLSIZE) <= w->f_pos || track->frame.timecode == 0)) { */
		/* CuePoint */
		if ((c = mk_createContext(w, w->cues, MATROSKA_ID_CUEPOINT)) == NULL)
			return -1;
		/* CueTime */
		CHECK(mk_writeUInt(c, MATROSKA_ID_CUETIME, (track->frame.timecode / w->timescale)));

		/* CueTrackPositions */
		if ((tp = mk_createContext(w, c, MATROSKA_ID_CUETRACKPOSITIONS)) == NULL)
			return -1;
		/* CueTrack */
		CHECK(mk_writeUInt(tp, MATROSKA_ID_CUETRACK, track->track_id));
		/* CueClusterPosition */
		CHECK(mk_writeUInt(tp, MATROSKA_ID_CUECLUSTERPOSITION, w->cluster.pointer));
		/* CueBlockNumber */
/*		CHECK(mk_writeUInt(c, MATROSKA_ID_CUEBLOCKNUMBER, w->cluster.block_count)); */
		CHECK(mk_closeContext(tp, 0));
		CHECK(mk_closeContext(c, 0));
		track->prev_cue_pos = w->f_pos;
	}

	track->in_frame = 0;
	track->prev_frame_tc_scaled = w->cluster.tc_scaled + delta;

	return 0;
}
コード例 #5
0
ファイル: matroska.c プロジェクト: wmertens/libmkv
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;
}
コード例 #6
0
ファイル: matroska.c プロジェクト: GamerCode/EasyRTMP
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;
}