/// <summary> /// write out the main header /// </summary> void writemainheader() { // note: this file starttag not actually part of main headers var tmp = Encoding.ASCII.GetBytes("nut/multimedia container\0"); output.Write(tmp, 0, tmp.Length); var header = new NutPacket(NutPacket.StartCode.Main, output); WriteVarU(3, header); // version WriteVarU(2, header); // stream_count WriteVarU(65536, header); // max_distance WriteVarU(2, header); // time_base_count // timebase is length of single frame, so reversed num+den is intentional WriteVarU(avparams.fpsden, header); // time_base_num[0] WriteVarU(avparams.fpsnum, header); // time_base_den[0] WriteVarU(1, header); // time_base_num[1] WriteVarU(avparams.samplerate, header); // time_base_den[1] // frame flag compression is ignored for simplicity for (int i = 0; i < 255; i++) // not 256 because entry 0x4e is skipped (as it would indicate a startcode) { WriteVarU((1 << 12), header); // tmp_flag = FLAG_CODED WriteVarU(0, header); // tmp_fields } // header compression ignored because it's not useful to us WriteVarU(0, header); // header_count_minus1 // BROADCAST_MODE only useful for realtime transmission clock recovery WriteVarU(0, header); // main_flags header.Flush(); }
/// <param name="payload">frame data</param> /// <param name="payLoadLen">actual length of frame data</param> /// <param name="pts">presentation timestamp</param> /// <param name="ptsNum">numerator of timebase</param> /// <param name="ptsDen">denominator of timebase</param> /// <param name="ptsIndex">which timestamp base is used, assumed to be also stream number</param> public NutFrame(byte[] payload, int payLoadLen, ulong pts, ulong ptsNum, ulong ptsDen, int ptsIndex, ReusableBufferPool <byte> pool) { _pts = pts; _ptsNum = ptsNum; _ptsDen = ptsDen; _pool = pool; _data = pool.GetBufferAtLeast(payLoadLen + 2048); var frame = new MemoryStream(_data); // create syncpoint var sync = new NutPacket(NutPacket.StartCode.Syncpoint, frame); WriteVarU(pts * 2 + (ulong)ptsIndex, sync); // global_key_pts WriteVarU(1, sync); // back_ptr_div_16, this is wrong sync.Flush(); var frameHeader = new MemoryStream(); frameHeader.WriteByte(0); // frame_code // frame_flags = FLAG_CODED, so: int flags = 0; flags |= 1 << 0; // FLAG_KEY if (payLoadLen == 0) { flags |= 1 << 1; // FLAG_EOR } flags |= 1 << 3; // FLAG_CODED_PTS flags |= 1 << 4; // FLAG_STREAM_ID flags |= 1 << 5; // FLAG_SIZE_MSB flags |= 1 << 6; // FLAG_CHECKSUM WriteVarU(flags, frameHeader); WriteVarU(ptsIndex, frameHeader); // stream_id WriteVarU(pts + 256, frameHeader); // coded_pts = pts + 1 << msb_pts_shift WriteVarU(payLoadLen, frameHeader); // data_size_msb var frameHeaderArr = frameHeader.ToArray(); frame.Write(frameHeaderArr, 0, frameHeaderArr.Length); WriteBe32(NutCRC32(frameHeaderArr), frame); // checksum frame.Write(payload, 0, payLoadLen); _actualLength = (int)frame.Position; }
/// <summary> /// write out the 1st stream header (audio) /// </summary> void writeaudioheader() { var header = new NutPacket(NutPacket.StartCode.Stream, output); WriteVarU(1, header); // stream_id WriteVarU(1, header); // stream_class = audio WriteString("\x01\x00\x00\x00", header); // fourcc = 01 00 00 00 WriteVarU(1, header); // time_base_id = 1 WriteVarU(8, header); // msb_pts_shift WriteVarU(avparams.samplerate, header); // max_pts_distance WriteVarU(0, header); // decode_delay WriteVarU(0, header); // stream_flags = none; no FIXED_FPS because we aren't guaranteeing same-size audio chunks WriteBytes(new byte[0], header); // codec_specific_data // stream_class = audio WriteVarU(avparams.samplerate, header); // samplerate_num WriteVarU(1, header); // samplerate_den WriteVarU(avparams.channels, header); // channel_count header.Flush(); }
/// <summary> /// write out the 0th stream header (video) /// </summary> void writevideoheader() { var header = new NutPacket(NutPacket.StartCode.Stream, output); WriteVarU(0, header); // stream_id WriteVarU(0, header); // stream_class = video WriteString("BGRA", header); // fourcc = "BGRA" WriteVarU(0, header); // time_base_id = 0 WriteVarU(8, header); // msb_pts_shift WriteVarU(1, header); // max_pts_distance WriteVarU(0, header); // decode_delay WriteVarU(1, header); // stream_flags = FLAG_FIXED_FPS WriteBytes(new byte[0], header); // codec_specific_data // stream_class = video WriteVarU(avparams.width, header); // width WriteVarU(avparams.height, header); // height WriteVarU(1, header); // sample_width WriteVarU(1, header); // sample_height WriteVarU(18, header); // colorspace_type = full range rec709 (avisynth's "PC.709") header.Flush(); }