Exemple #1
0
void EbmlComposer::FinishCluster()
{
  FinishMetadata();
  if (!(mFlushState & FLUSH_CLUSTER)) {
    // No completed cluster available.
    return;
  }

  MOZ_ASSERT(mClusterLengthLoc > 0);
  EbmlGlobal ebml;
  EbmlLoc ebmlLoc;
  ebmlLoc.offset = mClusterLengthLoc;
  ebml.offset = 0;
  for (uint32_t i = mClusterHeaderIndex; i < mClusterBuffs.Length(); i++) {
    ebml.offset += mClusterBuffs[i].Length();
  }
  ebml.buf = mClusterBuffs[mClusterHeaderIndex].Elements();
  Ebml_EndSubElement(&ebml, &ebmlLoc);
  // Move the mClusterBuffs data from mClusterHeaderIndex that we can skip
  // the metadata and the rest P-frames after ContainerWriter::FLUSH_NEEDED.
  for (uint32_t i = mClusterHeaderIndex; i < mClusterBuffs.Length(); i++) {
    mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]);
  }

  mClusterHeaderIndex = 0;
  mClusterLengthLoc = 0;
  mClusterBuffs.Clear();
  mFlushState &= ~FLUSH_CLUSTER;
}
int main(int argc, char *argv[]) {
  // init the datatype we're using for ebml output
  unsigned char data[8192];
  EbmlGlobal ebml;
  ebml.buf = data;
  ebml.offset = 0;
  ebml.length = 8192;

  writeHeader(&ebml);
  {
    EbmlLoc startSegment;
    Ebml_StartSubElement(&ebml, &startSegment, Segment); // segment
    {
      // segment info
      EbmlLoc startInfo;
      Ebml_StartSubElement(&ebml, &startInfo, Info);
      Ebml_SerializeString(&ebml, 0x4D80, "muxingAppLibMkv");
      Ebml_SerializeString(&ebml, 0x5741, "writingAppLibMkv");
      Ebml_EndSubElement(&ebml, &startInfo);
    }

    {
      EbmlLoc trackStart;
      Ebml_StartSubElement(&ebml, &trackStart, Tracks);
      writeVideoTrack(&ebml, 1, 1, "V_MS/VFW/FOURCC", 320, 240, 29.97);
      // writeAudioTrack(&ebml,2,1, "A_VORBIS", 32000, 1, NULL, 0);
      Ebml_EndSubElement(&ebml, &trackStart);
    }

    {
      EbmlLoc clusterStart;
      Ebml_StartSubElement(&ebml, &clusterStart, Cluster); // cluster
      Ebml_SerializeUnsigned(&ebml, Timecode, 0);

      unsigned char someData[4] = {1, 2, 3, 4};
      writeSimpleBlock(&ebml, 1, 0, 1, 0, 0, someData, 4);
      Ebml_EndSubElement(&ebml, &clusterStart);
    }    // end cluster
    Ebml_EndSubElement(&ebml, &startSegment);
  }

  // dump ebml stuff to the file
  FILE *file_out = fopen("test.mkv", "wb");
  size_t bytesWritten = fwrite(data, 1, ebml.offset, file_out);
  fclose(file_out);
  return 0;
}
Exemple #3
0
void EbmlComposer::GenerateHeader()
{
  // Write the EBML header.
  EbmlGlobal ebml;
  // The WEbM header default size usually smaller than 1k.
  nsAutoArrayPtr<uint8_t> buffer(new uint8_t[DEFAULT_HEADER_SIZE +
                                             mCodecPrivateData.Length()]);
  ebml.buf = buffer.get();
  ebml.offset = 0;
  writeHeader(&ebml);
  {
    EbmlLoc segEbmlLoc, ebmlLocseg, ebmlLoc;
    Ebml_StartSubElement(&ebml, &segEbmlLoc, Segment);
    {
      Ebml_StartSubElement(&ebml, &ebmlLocseg, SeekHead);
      // Todo: We don't know the exact sizes of encoded data and ignore this section.
      Ebml_EndSubElement(&ebml, &ebmlLocseg);
      writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0);
      {
        EbmlLoc trackLoc;
        Ebml_StartSubElement(&ebml, &trackLoc, Tracks);
        {
          // Video
          if (mWidth > 0 && mHeight > 0) {
            writeVideoTrack(&ebml, 0x1, 0, "V_VP8",
                            mWidth, mHeight, mFrameRate);
          }
          // Audio
          if (mCodecPrivateData.Length() > 0) {
            writeAudioTrack(&ebml, 0x2, 0x0, "A_VORBIS", mSampleFreq,
                            mChannels, mCodecPrivateData.Elements(),
                            mCodecPrivateData.Length());
          }
        }
        Ebml_EndSubElement(&ebml, &trackLoc);
      }
    }
    // The Recording length is unknow and ignore write the whole Segment element size
  }
  MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
                "write more data > EBML_BUFFER_SIZE");
  mClusterBuffs.AppendElement();
  mClusterBuffs.LastElement().SetLength(ebml.offset);
  memcpy(mClusterBuffs.LastElement().Elements(), ebml.buf, ebml.offset);
}
//------------------------------------------------------------------
void write_webm_seek_element(EbmlGlobal *global, unsigned int id, off_t pos)
{
	uint64_t offset = pos - global->position_reference;
	off_t start;
	Ebml_StartSubElement(global, &start, Seek);
	Ebml_SerializeBinary(global, SeekID, id);
	Ebml_SerializeUnsigned64(global, SeekPosition, offset);
	Ebml_EndSubElement(global, &start);
}
Exemple #5
0
void write_webm_seek_element(struct EbmlGlobal *ebml,
                             unsigned int id,
                             off_t pos) {
  uint64_t offset = pos - ebml->position_reference;
  EbmlLoc start;
  Ebml_StartSubElement(ebml, &start, Seek);
  Ebml_SerializeBinary(ebml, SeekID, id);
  Ebml_SerializeUnsigned64(ebml, SeekPosition, offset);
  Ebml_EndSubElement(ebml, &start);
}
//------------------------------------------------------------------
void write_webm_file_footer(EbmlGlobal *global, int hash)
{
	off_t start_cues;
	off_t start_cue_point;
	off_t start_cue_tracks;
	unsigned int i;

	if (global->cluster_open)
	{
		Ebml_EndSubElement(global, &global->startCluster);
	}

	global->cue_pos = ftello(global->stream);
	Ebml_StartSubElement(global, &start_cues, Cues);

	for (i = 0; i < global->cues; i++)
	{
		struct cue_entry *cue = &global->cue_list[i];
		Ebml_StartSubElement(global, &start_cue_point, CuePoint);
		Ebml_SerializeUnsigned(global, CueTime, cue->time);

		Ebml_StartSubElement(global, &start_cue_tracks, CueTrackPositions);
		Ebml_SerializeUnsigned(global, CueTrack, 1);
		Ebml_SerializeUnsigned64(global, CueClusterPosition, cue->loc - global->position_reference);
		Ebml_EndSubElement(global, &start_cue_tracks);

		Ebml_EndSubElement(global, &start_cue_point);
	}

	Ebml_EndSubElement(global, &start_cues);

	/* Close the Segment. */
	Ebml_EndSubElement(global, &global->startSegment);

	/* Patch up the seek info block. */
	write_webm_seek_info(global);

	/* Patch up the track id. */
	fseeko(global->stream, global->track_id_pos, SEEK_SET);
	Ebml_SerializeUnsigned32(global, TrackUID, hash);

	fseeko(global->stream, 0, SEEK_END);
}
Exemple #7
0
void write_webm_seek_info(struct EbmlGlobal *ebml) {
  off_t pos;
  EbmlLoc start;
  EbmlLoc startInfo;
  uint64_t frame_time;
  char version_string[64];

  /* Save the current stream pointer. */
  pos = ftello(ebml->stream);

  if (ebml->seek_info_pos)
    fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET);
  else
    ebml->seek_info_pos = pos;

  Ebml_StartSubElement(ebml, &start, SeekHead);
  write_webm_seek_element(ebml, Tracks, ebml->track_pos);
  write_webm_seek_element(ebml, Cues, ebml->cue_pos);
  write_webm_seek_element(ebml, Info, ebml->segment_info_pos);
  Ebml_EndSubElement(ebml, &start);

  /* Create and write the Segment Info. */
  if (ebml->debug) {
    strcpy(version_string, "vpxenc");
  } else {
    strcpy(version_string, "vpxenc ");
    strncat(version_string,
            vpx_codec_version_str(),
            sizeof(version_string) - 1 - strlen(version_string));
  }

  frame_time = (uint64_t)1000 * ebml->framerate.den
               / ebml->framerate.num;
  ebml->segment_info_pos = ftello(ebml->stream);
  Ebml_StartSubElement(ebml, &startInfo, Info);
  Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000);
  Ebml_SerializeFloat(ebml, Segment_Duration,
                      (double)(ebml->last_pts_ms + frame_time));
  Ebml_SerializeString(ebml, 0x4D80, version_string);
  Ebml_SerializeString(ebml, 0x5741, version_string);
  Ebml_EndSubElement(ebml, &startInfo);
}
void writeHeader(EbmlGlobal *glob) {
  EbmlLoc start;
  Ebml_StartSubElement(glob, &start, EBML);
  Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
  Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); 
  Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); 
  Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); 
  Ebml_SerializeString(glob, DocType, "webm"); 
  Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); 
  Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); 
  Ebml_EndSubElement(glob, &start);
}
//------------------------------------------------------------------
void write_webm_seek_info(EbmlGlobal *global)
{
	off_t pos;
	off_t start;
	off_t startInfo;
	uint64_t frame_time;
	char version_string[64];

	/* Save the current stream pointer. */
	pos = ftello(global->stream);

	if (global->seek_info_pos)
	{
		fseeko(global->stream, global->seek_info_pos, SEEK_SET);
	}
	else
	{
		global->seek_info_pos = pos;
	}

	Ebml_StartSubElement(global, &start, SeekHead);
	write_webm_seek_element(global, Tracks, global->track_pos);
	write_webm_seek_element(global, Cues, global->cue_pos);
	write_webm_seek_element(global, Info, global->segment_info_pos);
	Ebml_EndSubElement(global, &start);

	/* Create and write the Segment Info. */
	strcpy(version_string, "DesktopCapture v1.0 - libVPX ");
	strncat(version_string, vpx_codec_version_str(), sizeof(version_string) - 1 - strlen(version_string));

	frame_time = (uint64_t) 1000 * global->framerate.den / global->framerate.num;

	global->segment_info_pos = ftello(global->stream);
	Ebml_StartSubElement(global, &startInfo, Info);
	Ebml_SerializeUnsigned(global, TimecodeScale, 1000000);
	Ebml_SerializeFloat(global, Segment_Duration, (double) (global->last_pts_ms + frame_time));
	Ebml_SerializeString(global, MuxingApp, version_string);
	Ebml_SerializeString(global, WritingApp, version_string);
	Ebml_EndSubElement(global, &startInfo);
}
void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                     char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
                     double frameRate) {
  EbmlLoc start;
  Ebml_StartSubElement(glob, &start, TrackEntry);
  Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
  UInt64 trackID = generateTrackID(trackNumber);
  Ebml_SerializeUnsigned(glob, TrackUID, trackID);
  Ebml_SerializeString(glob, CodecName, "VP8");  

  Ebml_SerializeUnsigned(glob, TrackType, 1); 
  Ebml_SerializeString(glob, CodecID, codecId);
  {
    EbmlLoc videoStart;
    Ebml_StartSubElement(glob, &videoStart, Video);
    Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
    Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
    Ebml_SerializeFloat(glob, FrameRate, frameRate);
    Ebml_EndSubElement(glob, &videoStart); 
  }
  Ebml_EndSubElement(glob, &start); 
}
Exemple #11
0
void EbmlComposer::FinishCluster()
{
  MOZ_ASSERT(mClusterLengthLoc > 0 );
  MOZ_ASSERT(mClusterHeaderIndex > 0);
  for (uint32_t i = 0; i < mClusterBuffs.Length(); i ++ ) {
    mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]);
  }
  mClusterBuffs.Clear();
  EbmlGlobal ebml;
  EbmlLoc ebmlLoc;
  ebmlLoc.offset = mClusterLengthLoc;
  ebml.offset = mClusterCanFlushBuffs[mClusterHeaderIndex].Length();
  ebml.buf = mClusterCanFlushBuffs[mClusterHeaderIndex].Elements();
  Ebml_EndSubElement(&ebml, &ebmlLoc);
  mClusterHeaderIndex = 0;
  mClusterLengthLoc = 0;
}
Exemple #12
0
void write_webm_block(struct EbmlGlobal *glob,
                      const vpx_codec_enc_cfg_t *cfg,
                      const vpx_codec_cx_pkt_t *pkt) {
  unsigned int block_length;
  unsigned char track_number;
  uint16_t block_timecode = 0;
  unsigned char flags;
  int64_t pts_ms;
  int start_cluster = 0, is_keyframe;

  /* Calculate the PTS of this frame in milliseconds. */
  pts_ms = pkt->data.frame.pts * 1000
           * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;

  if (pts_ms <= glob->last_pts_ms)
    pts_ms = glob->last_pts_ms + 1;

  glob->last_pts_ms = pts_ms;

  /* Calculate the relative time of this block. */
  if (pts_ms - glob->cluster_timecode > SHRT_MAX)
    start_cluster = 1;
  else
    block_timecode = (uint16_t)pts_ms - glob->cluster_timecode;

  is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY);
  if (start_cluster || is_keyframe) {
    if (glob->cluster_open)
      Ebml_EndSubElement(glob, &glob->startCluster);

    /* Open the new cluster. */
    block_timecode = 0;
    glob->cluster_open = 1;
    glob->cluster_timecode = (uint32_t)pts_ms;
    glob->cluster_pos = ftello(glob->stream);
    Ebml_StartSubElement(glob, &glob->startCluster, Cluster);
    Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode);

    /* Save a cue point if this is a keyframe. */
    if (is_keyframe) {
      struct cue_entry *cue, *new_cue_list;

      new_cue_list = realloc(glob->cue_list,
                             (glob->cues + 1) * sizeof(struct cue_entry));
      if (new_cue_list)
        glob->cue_list = new_cue_list;
      else
        fatal("Failed to realloc cue list.");

      cue = &glob->cue_list[glob->cues];
      cue->time = glob->cluster_timecode;
      cue->loc = glob->cluster_pos;
      glob->cues++;
    }
  }

  /* Write the Simple Block. */
  Ebml_WriteID(glob, SimpleBlock);

  block_length = (unsigned int)pkt->data.frame.sz + 4;
  block_length |= 0x10000000;
  Ebml_Serialize(glob, &block_length, sizeof(block_length), 4);

  track_number = 1;
  track_number |= 0x80;
  Ebml_Write(glob, &track_number, 1);

  Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2);

  flags = 0;
  if (is_keyframe)
    flags |= 0x80;
  if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
    flags |= 0x08;
  Ebml_Write(glob, &flags, 1);

  Ebml_Write(glob, pkt->data.frame.buf, (unsigned int)pkt->data.frame.sz);
}