Beispiel #1
0
static int	  mk_writeSize(mk_Context *c, unsigned size) {
#ifndef __CW32__
  unsigned char	  c_size[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };
#else
  unsigned char	  c_size[5];
  c_size[0] = 0x08;
  c_size[1] = size >> 24;
  c_size[2] = size >> 16;
  c_size[3] = size >> 8;
  c_size[4] = size;
#endif

  if (size < 0x7f) {
    c_size[4] |= 0x80;
    return mk_appendContextData(c, c_size+4, 1);
  }
  if (size < 0x3fff) {
    c_size[3] |= 0x40;
    return mk_appendContextData(c, c_size+3, 2);
  }
  if (size < 0x1fffff) {
    c_size[2] |= 0x20;
    return mk_appendContextData(c, c_size+2, 3);
  }
  if (size < 0x0fffffff) {
    c_size[1] |= 0x10;
    return mk_appendContextData(c, c_size+1, 4);
  }
  return mk_appendContextData(c, c_size, 5);
}
Beispiel #2
0
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;
}
Beispiel #3
0
static int	  mk_writeID(mk_Context *c, unsigned id) {
  unsigned char	  c_id[4] = { id >> 24, id >> 16, id >> 8, id };

  if (c_id[0])
    return mk_appendContextData(c, c_id, 4);
  if (c_id[1])
    return mk_appendContextData(c, c_id+1, 3);
  if (c_id[2])
    return mk_appendContextData(c, c_id+2, 2);
  return mk_appendContextData(c, c_id+3, 1);
}
Beispiel #4
0
static int  	  mk_writeSInt(mk_Context *c, unsigned id, int64_t si) {
#ifdef __CW32__
  unsigned char	  c_si[8];
#else
  unsigned char	  c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
#endif
  unsigned	  i = 0;
#ifdef __CW32__
  c_si[0] = si >> 56;
  c_si[1] = si >> 48;
  c_si[2] = si >> 40;
  c_si[3] = si >> 32;
  c_si[4] = si >> 24;
  c_si[5] = si >> 16;
  c_si[6] = si >> 8;
  c_si[7] = si;
#endif

  CHECK(mk_writeID(c, id));
  if (si < 0)
    while (i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80)
      ++i;
  else
    while (i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80))
      ++i;
  CHECK(mk_writeSize(c, 8 - i));
  CHECK(mk_appendContextData(c, c_si+i, 8 - i));
  return 0;
}
Beispiel #5
0
static int	  mk_writeUInt(mk_Context *c, unsigned id, int64_t ui) {
#ifdef __CW32__
  unsigned char	  c_ui[8];
#else
  unsigned char	  c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
#endif
  unsigned	  i = 0;
#ifdef __CW32__
  c_ui[0] = ui >> 56;
  c_ui[1] = ui >> 48;
  c_ui[2] = ui >> 40;
  c_ui[3] = ui >> 32;
  c_ui[4] = ui >> 24;
  c_ui[5] = ui >> 16;
  c_ui[6] = ui >> 8;
  c_ui[7] = ui;
#endif

  CHECK(mk_writeID(c, id));
  while (i < 7 && c_ui[i] == 0)
    ++i;
  CHECK(mk_writeSize(c, 8 - i));
  CHECK(mk_appendContextData(c, c_ui+i, 8 - i));
  return 0;
}
Beispiel #6
0
static int	  mk_writeStr(mk_Context *c, unsigned id, const char *str) {
  size_t  len = strlen(str);

  CHECK(mk_writeID(c, id));
  CHECK(mk_writeSize(c, len));
  CHECK(mk_appendContextData(c, str, len));
  return 0;
}
Beispiel #7
0
static int	  mk_writeID(mk_Context *c, unsigned id) {
#ifndef __CW32__
  unsigned char	  c_id[4] = { id >> 24, id >> 16, id >> 8, id };
#else
  unsigned char	  c_id[4];
  c_id[0] = id >> 24;
  c_id[1] = id >> 16;
  c_id[2] = id >> 8;
  c_id[3] = id;
#endif

  if (c_id[0])
    return mk_appendContextData(c, c_id, 4);
  if (c_id[1])
    return mk_appendContextData(c, c_id+1, 3);
  if (c_id[2])
    return mk_appendContextData(c, c_id+2, 2);
  return mk_appendContextData(c, c_id+3, 1);
}
Beispiel #8
0
int	  mk_addFrameData(mk_Writer *w, const void *data, unsigned size) {
  if (!w->in_frame)
    return -1;

  if (w->frame == NULL)
    if ((w->frame = mk_createContext(w, NULL, 0)) == NULL)
      return -1;

  return mk_appendContextData(w->frame, data, size);
}
Beispiel #9
0
static int	  mk_writeUInt(mk_Context *c, unsigned id, int64_t ui) {
  unsigned char	  c_ui[8] = { ui >> 56, ui >> 48, ui >> 40, ui >> 32, ui >> 24, ui >> 16, ui >> 8, ui };
  unsigned	  i = 0;

  CHECK(mk_writeID(c, id));
  while (i < 7 && c_ui[i] == 0)
    ++i;
  CHECK(mk_writeSize(c, 8 - i));
  CHECK(mk_appendContextData(c, c_ui+i, 8 - i));
  return 0;
}
Beispiel #10
0
static int	  mk_writeSize(mk_Context *c, unsigned size) {
  unsigned char	  c_size[5] = { 0x08, size >> 24, size >> 16, size >> 8, size };

  if (size < 0x7f) {
    c_size[4] |= 0x80;
    return mk_appendContextData(c, c_size+4, 1);
  }
  if (size < 0x3fff) {
    c_size[3] |= 0x40;
    return mk_appendContextData(c, c_size+3, 2);
  }
  if (size < 0x1fffff) {
    c_size[2] |= 0x20;
    return mk_appendContextData(c, c_size+2, 3);
  }
  if (size < 0x0fffffff) {
    c_size[1] |= 0x10;
    return mk_appendContextData(c, c_size+1, 4);
  }
  return mk_appendContextData(c, c_size, 5);
}
Beispiel #11
0
static int	  mk_flushContextID(mk_Context *c) {
  unsigned char	ff = 0xff;

  if (c->id == 0)
    return 0;

  CHECK(mk_writeID(c->parent, c->id));
  CHECK(mk_appendContextData(c->parent, &ff, 1));

  c->id = 0;

  return 0;
}
Beispiel #12
0
static int	  mk_flushContextData(mk_Context *c) {
  if (c->d_cur == 0)
    return 0;

  if (c->parent)
    CHECK(mk_appendContextData(c->parent, c->data, c->d_cur));
  else
    if (fwrite(c->data, c->d_cur, 1, c->owner->fp) != 1)
      return -1;

  c->d_cur = 0;

  return 0;
}
Beispiel #13
0
int mk_addFrameData(mk_Writer *w, mk_Track *track, const void *data,
					unsigned size)
{
	if (!track->in_frame)
		return -1;

	if (track->frame.data == NULL) {
		if ((track->frame.data = mk_createContext(w, NULL, 0)) == NULL)
			return -1;
	}

	md5_update(&w->segment_md5, (unsigned char *) data, size);

	return mk_appendContextData(track->frame.data, data, size);
}
Beispiel #14
0
static int	  mk_writeFloatRaw(mk_Context *c, float f) {
  union {
    float f;
    unsigned u;
  } u;
  unsigned char	c_f[4];

  u.f = f;
  c_f[0] = u.u >> 24;
  c_f[1] = u.u >> 16;
  c_f[2] = u.u >> 8;
  c_f[3] = u.u;

  return mk_appendContextData(c, c_f, 4);
}
Beispiel #15
0
static int  	  mk_writeSInt(mk_Context *c, unsigned id, int64_t si) {
  unsigned char	  c_si[8] = { si >> 56, si >> 48, si >> 40, si >> 32, si >> 24, si >> 16, si >> 8, si };
  unsigned	  i = 0;

  CHECK(mk_writeID(c, id));
  if (si < 0)
    while (i < 7 && c_si[i] == 0xff && c_si[i+1] & 0x80)
      ++i;
  else
    while (i < 7 && c_si[i] == 0 && !(c_si[i+1] & 0x80))
      ++i;
  CHECK(mk_writeSize(c, 8 - i));
  CHECK(mk_appendContextData(c, c_si+i, 8 - i));
  return 0;
}
Beispiel #16
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;
}
Beispiel #17
0
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;
}
Beispiel #18
0
static int	  mk_writeBin(mk_Context *c, unsigned id, const void *data, unsigned size) {
  CHECK(mk_writeID(c, id));
  CHECK(mk_writeSize(c, size));
  CHECK(mk_appendContextData(c, data, size));
  return 0;
}