/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * multiplexer.cc * * Wed Aug 31 13:05:18 CEST 2005 * Copyright 2005 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of MIaV. * * MIaV is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MIaV is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MIaV; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "config.h" #include "multiplexer.h" #include "info.h" #include #include #include "util.h" #define SIZEOF(x) (sizeof(x)-1) #define MASK3 0x7 #define MASK15 0x7FFF #define TIMECODE32_30(x) ((x >> 30) & MASK3 ) #define TIMECODE29_15(x) ((x >> 15) & MASK15) #define TIMECODE14_0(x) ((x >> 0) & MASK15) // Audio index lists /* static unsigned int frequency_index[4] = {44100, 48000, 32000, 0}; //static unsigned int slots [4] = {12, 144, 0, 0}; //static unsigned int slot_index [4] = {144, 144, 144, 0}; //static unsigned int sample_index [4] = {384, 1152, 0, 0}; static unsigned int bitrate_index [4][16] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0}, // Reserved {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, // Layer III {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, // Layer II {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0} // Layer I }; static char layer_index[4][12] = { "Reserved", "Layer III", "Layer II", "Layer I" }; static char mode_index[4][32] = { "Stereo", "Joint Stereo", "Dual Channel", "Single Channel"}; static char protection_index[2][32] = { "CRC check enabled", "CRC check disabled" }; */ //static unsigned short int syncword = 0xFFF; // Video index lists /* #define FORBIDDEN -1.0 #define RESERVED -2.0 static double picture_rate_index[16] = { FORBIDDEN, 23.976, 24.0, 25.0, 29.97, 30.0, 50.0, 59.94, 60, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED }; */ Multiplexer::Multiplexer(File *f, Multicast *m, volatile bool *r, ThreadSafeQueuePriority *video_q, ThreadSafeQueuePriority *audio_q) { running = r; file = f; multicast = m; frame[TYPE_VIDEO] = NULL; written[TYPE_VIDEO] = 0.0; frame[TYPE_AUDIO] = NULL; written[TYPE_AUDIO] = 0.0; write_audio_packet = 0; write_system_header = 0; audio_header_read = false; queue[TYPE_VIDEO] = video_q; queue[TYPE_AUDIO] = audio_q; SCR = 3904;//0x40010003LL;//0x1E80; } Multiplexer::~Multiplexer() { } int Multiplexer::Write(void* data, int size) { int ret; if(multicast && multicast->multicast_audio == true) multicast->Write(data, size); ret = file->Write(data, size); return ret; } int Multiplexer::Write(char* data, int size) { return Write((void*)data, size); } int Multiplexer::Write(unsigned long long int val) { int res; int written = 0; unsigned long int h_u = val & 0xffffffff; unsigned long int h_l = (val << 32) & 0xffffffff; // *(unsigned long int *)(((char*)&val) + sizeof(unsigned long int)); h_u = htonl(h_u); h_l = htonl(h_l); if((res = Write(&h_l, sizeof(h_l))) < 0) { return res; } written += res; if((res = Write(&h_u, sizeof(h_u))) < 0) { return res; } written += res; return written; } int Multiplexer::Write(long long int val) { int res; int written = 0; unsigned long int h_u = val & 0xffffffff; unsigned long int h_l = (val << 32) & 0xffffffff; //*((unsigned long int *)(((char*)&val) + sizeof(unsigned long int))); h_u = htonl(h_u); h_l = htonl(h_l); if((res = Write(&h_l, sizeof(h_l))) < 0) { return res; } written += res; if((res = Write(&h_u, sizeof(h_u))) < 0) { return res; } written += res; return written; } int Multiplexer::Write(long int val) { val = htonl(val); return Write((char*)&val, sizeof(val)); } int Multiplexer::Write(unsigned long int val) { val = htonl(val); return Write((char*)&val, sizeof(val)); } int Multiplexer::Write(int val) { val = htonl(val); return Write((char*)&val, sizeof(val)); } int Multiplexer::Write(unsigned int val) { val = htonl(val); return Write((char*)&val, sizeof(val)); } int Multiplexer::Write(short int val) { val = htons(val); return Write((char*)&val, sizeof(val)); } int Multiplexer::Write(unsigned short int val) { val = htons(val); return Write((char*)&val, sizeof(val)); } Frame *Multiplexer::getFrame(StreamType type) { // MIaV::info->info("Get %s Frame", type==TYPE_AUDIO?"Audio\0":"Video\0"); read[type] = 0; Frame *frame = queue[type]->pop(); // If we multicast without audio, we better write the raw video stream. if(type == TYPE_VIDEO && multicast && multicast->multicast_audio == false) multicast->Write(frame->data, frame->size); return frame; } int Multiplexer::read_stream(char *buf, unsigned int size, StreamType type) { unsigned int copied = 0; while( copied < size ) { // If we read the entire frame, prepare to get a new one if(frame[type] && read[type] == frame[type]->size) { delete frame[type]; frame[type] = NULL; } // If no frame is in the buffer, get one from the queue if(frame[type] == NULL) frame[type] = getFrame(type); // check for end of stream if( frame[type]->endOfFrameStream == true) { MIaV::info->info("endOfFrameStream in Multiplexer %s-stream.", type==TYPE_VIDEO?"video\0":"audio\0"); return copied; } // If a frame exists in the buffer copy it to the output buffer // (No frame ocurres when *running is set to false) if( frame[type] ) { unsigned int doread = (size - copied) < (frame[type]->size - read[type]) ? size - copied : (frame[type]->size - read[type]); //MIaV::info->info("Requested: %d. Read: %d. Doread: %d. In buffer %d", size, (*read), doread, (*frame)->size); memcpy(buf + copied, frame[type]->data + read[type], doread); read[type] += doread; copied += doread; } } return copied; } bool Multiplexer::packet(StreamType type) { char buf[PACKET_SIZE]; // Write data // MIaV::info->info("\t\t[%sPacket]", type==TYPE_AUDIO?"Audio\0":"Video\0"); unsigned short int framesize = read_stream(buf, PACKET_SIZE, type); Write((void*)ISO11172_1::packet_start_code_prefix, SIZEOF(ISO11172_1::packet_start_code_prefix)); switch(type) { case TYPE_VIDEO: Write((void*)ISO11172_1::stream_id_video1, SIZEOF(ISO11172_1::stream_id_video1)); break; case TYPE_AUDIO: Write((void*)ISO11172_1::stream_id_audio1, SIZEOF(ISO11172_1::stream_id_audio1)); break; } ISO11172_1::packet_header header; header.bits.marker_bit1 = header.bits.marker_bit2 = header.bits.marker_bit3 = 1; header.bits.padding = 0x2; // Must be 2 header.bits.stuffing_byte = 0xFF; header.bits.packet_length = framesize + sizeof(ISO11172_1::packet_header) - sizeof(short); header.bits.system_clock_reference1 = TIMECODE32_30(SCR); header.bits.system_clock_reference2 = TIMECODE29_15(SCR); header.bits.system_clock_reference3 = TIMECODE14_0(SCR); Write(header.ulli); Write(buf, framesize); if(framesize != PACKET_SIZE) return false; written[type] += (double)PACKET_SIZE / (double)frame[type]->size;//bitrate; return true; } /** * Create and write a packet */ bool Multiplexer::packet() { //MIaV::info->info("\t\tWritten[A]: %f, Written[V]: %f", written[TYPE_AUDIO], written[TYPE_VIDEO]); StreamType type; /* // New switching mechanism if(written[TYPE_AUDIO] < written[TYPE_VIDEO]) { type = TYPE_AUDIO; } else { type = TYPE_VIDEO; } */ // Newer switching mechanism if(queue[TYPE_AUDIO]->size() > queue[TYPE_VIDEO]->size()) { type = TYPE_AUDIO; } else { type = TYPE_VIDEO; } if(!packet(type)) { // Flush the other stream too... if(type == TYPE_AUDIO) type = TYPE_VIDEO; else type = TYPE_AUDIO; while(packet(type)); return false; } return true; /* // Count this up here, we want audio packets in packet 4, 9, ... NOT 0, 3, ... write_audio_packet++; if(write_audio_packet % AUDIO_PACKET_FREQUENCY == 0) { packet(TYPE_AUDIO); } else { packet(TYPE_VIDEO); } */ } /** * Create and write the system header */ void Multiplexer::system_header() { // MIaV::info->info("\t\t[System Header]"); // system_header_start_code (32 bits) Write((void*)ISO11172_1::system_header_start_code, SIZEOF(ISO11172_1::system_header_start_code)); ISO11172_1::system_header header; header.bits.marker_bit1 = header.bits.marker_bit2 = header.bits.marker_bit3 = 1; header.bits.header_length = 8 - 2 + (NUM_TYPES * 3); // (sizeof(header) - sizeof(header.header_length)) + // NUM_TYPES * sizeof(ISO11172_1::stream_description); header.bits.rate_bound = 3521; // FIXME: Taken from the example! header.bits.audio_bound = 1; // Only 1 audio stream header.bits.fixed_flag = 1; // Fixed bitrate (0 indicates vbr) header.bits.CSPS_flag = 1; // Standarts compliant? (yes: see lame_set_strict_ISO in liblame_wrapper.cc) header.bits.system_audio_clock_flag = 1; // FIXME: What excactly is this?? header.bits.system_video_clock_flag = 1; // FIXME: What excactly is this?? header.bits.video_bound = 1; // Only 1 video stream header.bits.reserved_byte = 0xFF; // Must be 0xFF Write(header.ulli); ISO11172_1::stream_description audio_stream_description; audio_stream_description.bits.stream_id = 0xC0; audio_stream_description.bits.market_bits = 0x3; audio_stream_description.bits.STD_buffer_bound_scale = 0; // Must be 0 for audio streams audio_stream_description.bits.STD_buffer_size_bound = 32; // Buffer must be 32 * 128 bytes Write(audio_stream_description.uli); ISO11172_1::stream_description video_stream_description; video_stream_description.bits.stream_id = 0xE3; video_stream_description.bits.market_bits = 0x3; video_stream_description.bits.STD_buffer_bound_scale = 1; // Must be 1 for video streams video_stream_description.bits.STD_buffer_size_bound = 46; // Buffer must be 32 * 1024 bytes Write(video_stream_description.uli); } /** * Create and write a pack */ bool Multiplexer::pack() { // MIaV::info->info("\t[Pack"); Write((void*)ISO11172_1::pack_start_code, SIZEOF(ISO11172_1::pack_start_code)); ISO11172_1::pack_header header; // Set marker bits to 1 header.bits.marker_bit1 = header.bits.marker_bit2 = header.bits.marker_bit3 = header.bits.marker_bit4 = header.bits.marker_bit5 = 1; header.bits.padding = 0x2; unsigned int video_data_rate; unsigned int audio_data_rate; if(frame[TYPE_AUDIO]) audio_data_rate = frame[TYPE_AUDIO]->bitrate; else audio_data_rate = 112000; if(frame[TYPE_VIDEO]) video_data_rate = frame[TYPE_VIDEO]->bitrate; else video_data_rate = 1100000; unsigned int Rmux = ISO11172_1::Rmux(video_data_rate, audio_data_rate, 20, // packet_header_size, 12, // pack_header_size, PACKETS_PER_PACK, // packets_per_pack, PACKET_SIZE);// packet_data_size) header.bits.mux_rate = Rmux; //0x1B82; SCR = ISO11172_1::SCR(SCR, 12, //pack_header_size, PACKETS_PER_PACK, //packets_per_pack, PACKET_SIZE, //packet_data_size, Rmux); // SCR = 0x40010003LL; header.bits.system_clock_reference1 = TIMECODE32_30(SCR); header.bits.system_clock_reference2 = TIMECODE29_15(SCR); header.bits.system_clock_reference3 = TIMECODE14_0(SCR); /* MIaV::info->info("timecode All: %lld, 1: %lld, 2: %lld, 3: %lld", SCR, (unsigned long long int)header.system_clock_reference1, (unsigned long long int)header.system_clock_reference2, (unsigned long long int)header.system_clock_reference3 ); */ Write(header.ulli); if(write_system_header % SYSTEM_HEADER_FREQUENCY == 0) system_header(); // Count this up here, we want a system header in pack 0, 5, ... NOT 4, 9, ... write_system_header++; for(int cnt = 0; cnt < PACKETS_PER_PACK; cnt++) if(!packet()) return false; // MIaV::info->info("\t]"); return true; } /** * */ void Multiplexer::iso11172_stream() { // MIaV::info->info("[iso11172_stream"); while(pack()); // MIaV::info->info("]"); // MIaV::info->info("[iso11172_end_code]"); Write((void*)ISO11172_1::end_code, SIZEOF(ISO11172_1::end_code)); /* MIaV::info->info("false && false = %d", false && false); MIaV::info->info("true && false = %d", true && false); MIaV::info->info("true && true = %d", true && true); */ } //#define BYPASS TYPE_VIDEO //#define BYPASS TYPE_AUDIO void Multiplexer::multiplex() { #ifdef BYPASS int frmsz; char buf[1024]; do { frmsz = read_stream(buf, sizeof(buf), BYPASS); MIaV::info->info("Wrote %d bytes", frmsz); Write(buf, frmsz); } while(frmsz == sizeof(buf)); return; #else/*BYPASS*/ iso11172_stream(); #endif/*BYPASS*/ }