Merge branch 'DTSC' of github.com:DDVTECH/DMS into DTSC

This commit is contained in:
Erik Zandvliet 2012-04-23 19:00:57 +02:00
commit 6cf133226c
11 changed files with 244 additions and 237 deletions

View file

@ -5,6 +5,7 @@ INCLUDES =
DEBUG = 4 DEBUG = 4
OPTIMIZE = -g OPTIMIZE = -g
CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG)
INSTALL = install
CC = $(CROSS)g++ CC = $(CROSS)g++
LD = $(CROSS)ld LD = $(CROSS)ld
AR = $(CROSS)ar AR = $(CROSS)ar
@ -13,11 +14,11 @@ LIBS = -lpthread
.PHONY: clean default .PHONY: clean default
default: $(OUT) default: $(OUT)
.cpp.o: .cpp.o:
$(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@ $(CC) $(INCLUDES) $(CCFLAGS) -c $< -o $@ $(LIBS)
$(OUT): $(OBJ) $(OUT): $(OBJ)
$(CC) $(LIBS) -o $(OUT) $(OBJ) $(CC) -o $(OUT) $(OBJ) $(LIBS)
clean: clean:
rm -rf $(OBJ) $(OUT) Makefile.bak *~ rm -rf $(OBJ) $(OUT) Makefile.bak *~
install: $(OUT) install: $(OUT)
cp -f ./$(OUT) /usr/bin/ $(INSTALL) -D ./$(OUT) $(DESTDIR)/usr/bin/$(OUT)

View file

@ -6,6 +6,7 @@ DEBUG = 4
OPTIMIZE = -g OPTIMIZE = -g
CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) -DVERSION=$(VERSION) CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) -DVERSION=$(VERSION)
VERSION = `git describe --tags` VERSION = `git describe --tags`
INSTALL = install
CC = $(CROSS)g++ CC = $(CROSS)g++
LD = $(CROSS)ld LD = $(CROSS)ld
AR = $(CROSS)ar AR = $(CROSS)ar
@ -20,7 +21,7 @@ $(OUT): $(OBJ)
clean: clean:
rm -rf $(OBJ) $(OUT) Makefile.bak *~ rm -rf $(OBJ) $(OUT) Makefile.bak *~
install: $(OUT) install: $(OUT)
cp -f ./$(OUT) /usr/bin/ $(INSTALL) -D ./$(OUT) $(DESTDIR)/usr/bin/$(OUT)
cversion: cversion:
rm -rf ../util/config.o rm -rf ../util/config.o

View file

@ -5,6 +5,7 @@ INCLUDES =
DEBUG = 4 DEBUG = 4
OPTIMIZE = -g OPTIMIZE = -g
CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG)
INSTALL = install
CC = $(CROSS)g++ CC = $(CROSS)g++
LD = $(CROSS)ld LD = $(CROSS)ld
AR = $(CROSS)ar AR = $(CROSS)ar
@ -19,5 +20,5 @@ $(OUT): $(OBJ)
clean: clean:
rm -rf $(OBJ) $(OUT) Makefile.bak *~ rm -rf $(OBJ) $(OUT) Makefile.bak *~
install: $(OUT) install: $(OUT)
cp -f ./$(OUT) /usr/bin/ $(INSTALL) -D ./$(OUT) $(DESTDIR)/usr/bin/$(OUT)

View file

@ -6,6 +6,7 @@ STATIC =
DEBUG = 4 DEBUG = 4
OPTIMIZE = -g OPTIMIZE = -g
CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) -DVERSION=$(VERSION) CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) -DVERSION=$(VERSION)
INSTALL = install
CC = $(CROSS)g++ CC = $(CROSS)g++
LD = $(CROSS)ld LD = $(CROSS)ld
AR = $(CROSS)ar AR = $(CROSS)ar
@ -21,7 +22,7 @@ $(OUT): $(OBJ)
clean: clean:
rm -rf $(OBJ) $(OUT) Makefile.bak *~ rm -rf $(OBJ) $(OUT) Makefile.bak *~
install: $(OUT) install: $(OUT)
cp -f ./$(OUT) /usr/bin/ $(INSTALL) -D ./$(OUT) $(DESTDIR)/usr/bin/$(OUT)
cversion: cversion:
rm -rf ../util/config.o rm -rf ../util/config.o

View file

@ -10,6 +10,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <getopt.h> #include <getopt.h>
#include <sstream>
#include "../util/socket.h" #include "../util/socket.h"
#include "../util/flv_tag.h" #include "../util/flv_tag.h"
#include "../util/amf.h" #include "../util/amf.h"
@ -137,6 +138,12 @@ int Connector_RTMP::Connector_RTMP(Socket::Connection conn){
/// Tries to get and parse one RTMP chunk at a time. /// Tries to get and parse one RTMP chunk at a time.
void Connector_RTMP::parseChunk(std::string & inbuffer){ void Connector_RTMP::parseChunk(std::string & inbuffer){
//for DTSC conversion
static DTSC::DTMI meta_out;
static std::stringstream prebuffer; // Temporary buffer before sending real data
static bool sending = false;
static unsigned int counter = 0;
//for chunk parsing
static RTMPStream::Chunk next; static RTMPStream::Chunk next;
FLV::Tag F; FLV::Tag F;
static AMF::Object amfdata("empty", AMF::AMF0_DDV_CONTAINER); static AMF::Object amfdata("empty", AMF::AMF0_DDV_CONTAINER);
@ -209,32 +216,33 @@ void Connector_RTMP::parseChunk(std::string & inbuffer){
RTMPStream::snd_window_size = ntohl(*(int*)next.data.c_str()); RTMPStream::snd_window_size = ntohl(*(int*)next.data.c_str());
Socket.write(RTMPStream::SendCTL(5, RTMPStream::snd_window_size));//send window acknowledgement size (msg 5) Socket.write(RTMPStream::SendCTL(5, RTMPStream::snd_window_size));//send window acknowledgement size (msg 5)
break; break;
case 8: case 8://audio data
F.ChunkLoader(next); case 9://video data
case 18://meta data
if (SS.connected()){ if (SS.connected()){
#if DEBUG >= 4 F.ChunkLoader(next);
fprintf(stderr, "A"); DTSC::DTMI pack_out = F.toDTSC(meta_out);
#endif if (!pack_out.isEmpty()){
/// \TODO Convert to DTSC properly. if (!sending){
SS.write(std::string(F.data, F.len)); counter++;
if (counter > 8){
sending = true;
meta_out.Pack(true);//pack metadata
meta_out.packed.replace(0, 4, DTSC::Magic_Header);//prepare proper header
SS.write(meta_out.packed);//write header/metadata
SS.write(prebuffer.str());//write buffer
prebuffer.str("");//clear buffer
SS.write(pack_out.Pack(true));//simply write
}else{
prebuffer << pack_out.Pack(true);//buffer
}
}else{
SS.write(pack_out.Pack(true));//simple write
}
}
}else{ }else{
#if DEBUG >= 4 #if DEBUG >= 4
fprintf(stderr, "Received useless audio data\n"); fprintf(stderr, "Received useless media data\n");
#endif
Socket.close();
}
break;
case 9:
F.ChunkLoader(next);
if (SS.connected()){
#if DEBUG >= 4
fprintf(stderr, "V");
#endif
/// \TODO Convert to DTSC properly.
SS.write(std::string(F.data, F.len));
}else{
#if DEBUG >= 4
fprintf(stderr, "Received useless video data\n");
#endif #endif
Socket.close(); Socket.close();
} }
@ -268,15 +276,6 @@ void Connector_RTMP::parseChunk(std::string & inbuffer){
parseAMFCommand(amfdata, 17, next.msg_stream_id); parseAMFCommand(amfdata, 17, next.msg_stream_id);
}//parsing AMF0-style }//parsing AMF0-style
} break; } break;
case 18:
#if DEBUG >= 4
fprintf(stderr, "Received AFM0 data message (metadata)\n");
#endif
F.ChunkLoader(next);
if (SS.connected()){
SS.write(std::string(F.data, F.len));
}
break;
case 19: case 19:
#if DEBUG >= 4 #if DEBUG >= 4
fprintf(stderr, "Received AFM0 shared object\n"); fprintf(stderr, "Received AFM0 shared object\n");

View file

@ -9,6 +9,7 @@ COMPILED_USERNAME = testuser
COMPILED_PASSWORD = 179ad45c6ce2cb97cf1029e212046e81 COMPILED_PASSWORD = 179ad45c6ce2cb97cf1029e212046e81
#COMPILED_PASSWORD = testpass #COMPILED_PASSWORD = testpass
CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) -DCOMPILED_USERNAME=$(COMPILED_USERNAME) -DCOMPILED_PASSWORD=$(COMPILED_PASSWORD) -DVERSION=$(VERSION) CCFLAGS = -Wall -Wextra -funsigned-char $(OPTIMIZE) -DDEBUG=$(DEBUG) -DCOMPILED_USERNAME=$(COMPILED_USERNAME) -DCOMPILED_PASSWORD=$(COMPILED_PASSWORD) -DVERSION=$(VERSION)
INSTALL = install
CC = $(CROSS)g++ CC = $(CROSS)g++
LD = $(CROSS)ld LD = $(CROSS)ld
AR = $(CROSS)ar AR = $(CROSS)ar
@ -24,4 +25,6 @@ clean:
rm -rf $(OBJ) $(OUT) Makefile.bak *~ rm -rf $(OBJ) $(OUT) Makefile.bak *~
cversion: cversion:
rm -rf ../util/config.o rm -rf ../util/config.o
install: $(OUT)
$(INSTALL) -D ./$(OUT) $(DESTDIR)/usr/bin/$(OUT)

View file

@ -14,62 +14,12 @@
#include "../../util/dtsc.h" //DTSC support #include "../../util/dtsc.h" //DTSC support
#include "../../util/amf.h" //AMF support #include "../../util/amf.h" //AMF support
// String onMetaData
// ECMA Array
// Bool hasVideo 1
// Number videocodecid 4 (2 = H263, 4 = VP6, 7 = H264)
// Number width 320
// Number height 240
// Number framerate 23.976 (/ 1000)
// Number videodatarate 500.349 (kbps)
// Bool hasAudio 1
// Bool stereo 1
// Number audiodelay 0
// Number audiosamplerate 11025
// Number audiosamplesize 16
// Number audiocodecid 2 (2 = MP3, 10 = AAC)
// Number audiodatarate 64.3269 (kbps)
/// Holds all code that converts filetypes to DTSC. /// Holds all code that converts filetypes to DTSC.
namespace Converters{ namespace Converters{
/// Inserts std::string type metadata into the passed DTMI object.
/// \arg meta The DTMI object to put the metadata into.
/// \arg cat Metadata category to insert into.
/// \arg elem Element name to put into the category.
/// \arg val Value to put into the element name.
void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, std::string val){
if (meta.getContentP(cat) == 0){meta.addContent(DTSC::DTMI(cat));}
meta.getContentP(cat)->addContent(DTSC::DTMI(elem, val));
std::cerr << "Metadata " << cat << "." << elem << " = " << val << std::endl;
}
/// Inserts uint64_t type metadata into the passed DTMI object.
/// \arg meta The DTMI object to put the metadata into.
/// \arg cat Metadata category to insert into.
/// \arg elem Element name to put into the category.
/// \arg val Value to put into the element name.
void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, uint64_t val){
if (meta.getContentP(cat) == 0){meta.addContent(DTSC::DTMI(cat));}
meta.getContentP(cat)->addContent(DTSC::DTMI(elem, val));
std::cerr << "Metadata " << cat << "." << elem << " = " << val << std::endl;
}
/// Returns true if the named category and elementname are available in the metadata.
/// \arg meta The DTMI object to check.
/// \arg cat Metadata category to check.
/// \arg elem Element name to check.
bool Meta_Has(DTSC::DTMI & meta, std::string cat, std::string elem){
if (meta.getContentP(cat) == 0){return false;}
if (meta.getContentP(cat)->getContentP(elem) == 0){return false;}
return true;
}
/// Reads FLV from STDIN, outputs DTSC to STDOUT. /// Reads FLV from STDIN, outputs DTSC to STDOUT.
int FLV2DTSC() { int FLV2DTSC() {
FLV::Tag FLV_in; // Temporary storage for incoming FLV data. FLV::Tag FLV_in; // Temporary storage for incoming FLV data.
AMF::Object meta_in; // Temporary storage for incoming metadata.
DTSC::DTMI meta_out; // Storage for outgoing DTMI header data. DTSC::DTMI meta_out; // Storage for outgoing DTMI header data.
DTSC::DTMI pack_out; // Storage for outgoing DTMI data. DTSC::DTMI pack_out; // Storage for outgoing DTMI data.
std::stringstream prebuffer; // Temporary buffer before sending real data std::stringstream prebuffer; // Temporary buffer before sending real data
@ -78,9 +28,11 @@ namespace Converters{
while (!feof(stdin)){ while (!feof(stdin)){
if (FLV_in.FileLoader(stdin)){ if (FLV_in.FileLoader(stdin)){
pack_out = FLV_in.toDTSC(meta_out);
if (pack_out.isEmpty()){continue;}
if (!sending){ if (!sending){
counter++; counter++;
if (counter > 10){ if (counter > 8){
sending = true; sending = true;
meta_out.Pack(true); meta_out.Pack(true);
meta_out.packed.replace(0, 4, DTSC::Magic_Header); meta_out.packed.replace(0, 4, DTSC::Magic_Header);
@ -88,154 +40,12 @@ namespace Converters{
std::cout << prebuffer.rdbuf(); std::cout << prebuffer.rdbuf();
prebuffer.str(""); prebuffer.str("");
std::cerr << "Buffer done, starting real-time output..." << std::endl; std::cerr << "Buffer done, starting real-time output..." << std::endl;
}else{
prebuffer << pack_out.Pack(true);//buffer
continue;//don't also write
} }
} }
if (FLV_in.data[0] == 0x12){ std::cout << pack_out.Pack(true);//simply write
meta_in = AMF::parse((unsigned char*)FLV_in.data+11, FLV_in.len-15);
if (meta_in.getContentP(0) && (meta_in.getContentP(0)->StrValue() == "onMetaData") && meta_in.getContentP(1)){
AMF::Object * tmp = meta_in.getContentP(1);
if (tmp->getContentP("videocodecid")){
switch ((unsigned int)tmp->getContentP("videocodecid")->NumValue()){
case 2: Meta_Put(meta_out, "video", "codec", "H263"); break;
case 4: Meta_Put(meta_out, "video", "codec", "VP6"); break;
case 7: Meta_Put(meta_out, "video", "codec", "H264"); break;
default: Meta_Put(meta_out, "video", "codec", "?"); break;
}
}
if (tmp->getContentP("audiocodecid")){
switch ((unsigned int)tmp->getContentP("audiocodecid")->NumValue()){
case 2: Meta_Put(meta_out, "audio", "codec", "MP3"); break;
case 10: Meta_Put(meta_out, "audio", "codec", "AAC"); break;
default: Meta_Put(meta_out, "audio", "codec", "?"); break;
}
}
if (tmp->getContentP("width")){
Meta_Put(meta_out, "video", "width", tmp->getContentP("width")->NumValue());
}
if (tmp->getContentP("height")){
Meta_Put(meta_out, "video", "height", tmp->getContentP("height")->NumValue());
}
if (tmp->getContentP("framerate")){
Meta_Put(meta_out, "video", "fpks", tmp->getContentP("framerate")->NumValue()*1000);
}
if (tmp->getContentP("videodatarate")){
Meta_Put(meta_out, "video", "bps", (tmp->getContentP("videodatarate")->NumValue()*1024)/8);
}
if (tmp->getContentP("audiodatarate")){
Meta_Put(meta_out, "audio", "bps", (tmp->getContentP("audiodatarate")->NumValue()*1024)/8);
}
if (tmp->getContentP("audiosamplerate")){
Meta_Put(meta_out, "audio", "rate", tmp->getContentP("audiosamplerate")->NumValue());
}
if (tmp->getContentP("audiosamplesize")){
Meta_Put(meta_out, "audio", "size", tmp->getContentP("audiosamplesize")->NumValue());
}
if (tmp->getContentP("stereo")){
if (tmp->getContentP("stereo")->NumValue() == 1){
Meta_Put(meta_out, "audio", "channels", 2);
}else{
Meta_Put(meta_out, "audio", "channels", 1);
}
}
}
}
if (FLV_in.data[0] == 0x08){
char audiodata = FLV_in.data[11];
if (FLV_in.needsInitData() && FLV_in.isInitData()){
if ((audiodata & 0xF0) == 0xA0){
Meta_Put(meta_out, "audio", "init", std::string((char*)FLV_in.data+13, (size_t)FLV_in.len-17));
}else{
Meta_Put(meta_out, "audio", "init", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16));
}
continue;//skip rest of parsing, get next tag.
}
pack_out = DTSC::DTMI("audio", DTSC::DTMI_ROOT);
pack_out.addContent(DTSC::DTMI("datatype", "audio"));
pack_out.addContent(DTSC::DTMI("time", FLV_in.tagTime()));
if (!Meta_Has(meta_out, "audio", "codec")){
switch (audiodata & 0xF0){
case 0x20: Meta_Put(meta_out, "audio", "codec", "MP3"); break;
case 0xA0: Meta_Put(meta_out, "audio", "codec", "AAC"); break;
default: Meta_Put(meta_out, "audio", "codec", "?"); break;
}
}
if (!Meta_Has(meta_out, "audio", "rate")){
switch (audiodata & 0x0C){
case 0x0: Meta_Put(meta_out, "audio", "rate", 5512); break;
case 0x4: Meta_Put(meta_out, "audio", "rate", 11025); break;
case 0x8: Meta_Put(meta_out, "audio", "rate", 22050); break;
case 0xC: Meta_Put(meta_out, "audio", "rate", 44100); break;
}
}
if (!Meta_Has(meta_out, "audio", "size")){
switch (audiodata & 0x02){
case 0x0: Meta_Put(meta_out, "audio", "size", 8); break;
case 0x2: Meta_Put(meta_out, "audio", "size", 16); break;
}
}
if (!Meta_Has(meta_out, "audio", "channels")){
switch (audiodata & 0x01){
case 0x0: Meta_Put(meta_out, "audio", "channels", 1); break;
case 0x1: Meta_Put(meta_out, "audio", "channels", 2); break;
}
}
if ((audiodata & 0xF0) == 0xA0){
pack_out.addContent(DTSC::DTMI("data", std::string((char*)FLV_in.data+13, (size_t)FLV_in.len-17)));
}else{
pack_out.addContent(DTSC::DTMI("data", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16)));
}
if (sending){
std::cout << pack_out.Pack(true);
}else{
prebuffer << pack_out.Pack(true);
}
}
if (FLV_in.data[0] == 0x09){
char videodata = FLV_in.data[11];
if (FLV_in.needsInitData() && FLV_in.isInitData()){
if ((videodata & 0x0F) == 7){
Meta_Put(meta_out, "video", "init", std::string((char*)FLV_in.data+16, (size_t)FLV_in.len-20));
}else{
Meta_Put(meta_out, "video", "init", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16));
}
continue;//skip rest of parsing, get next tag.
}
if (!Meta_Has(meta_out, "video", "codec")){
switch (videodata & 0x0F){
case 2: Meta_Put(meta_out, "video", "codec", "H263"); break;
case 4: Meta_Put(meta_out, "video", "codec", "VP6"); break;
case 7: Meta_Put(meta_out, "video", "codec", "H264"); break;
default: Meta_Put(meta_out, "video", "codec", "?"); break;
}
}
pack_out = DTSC::DTMI("video", DTSC::DTMI_ROOT);
pack_out.addContent(DTSC::DTMI("datatype", "video"));
switch (videodata & 0xF0){
case 0x10: pack_out.addContent(DTSC::DTMI("keyframe", 1)); break;
case 0x20: pack_out.addContent(DTSC::DTMI("interframe", 1)); break;
case 0x30: pack_out.addContent(DTSC::DTMI("disposableframe", 1)); break;
case 0x40: pack_out.addContent(DTSC::DTMI("keyframe", 1)); break;
case 0x50: continue; break;//the video info byte we just throw away - useless to us...
}
pack_out.addContent(DTSC::DTMI("time", FLV_in.tagTime()));
if ((videodata & 0x0F) == 7){
switch (FLV_in.data[12]){
case 1: pack_out.addContent(DTSC::DTMI("nalu", 1)); break;
case 2: pack_out.addContent(DTSC::DTMI("nalu_end", 1)); break;
}
int offset = (FLV_in.data[13] << 16) + (FLV_in.data[14] << 8) + FLV_in.data[15];
offset = (offset << 8) >> 8;
pack_out.addContent(DTSC::DTMI("offset", offset));
pack_out.addContent(DTSC::DTMI("data", std::string((char*)FLV_in.data+16, (size_t)FLV_in.len-20)));
}else{
pack_out.addContent(DTSC::DTMI("data", std::string((char*)FLV_in.data+12, (size_t)FLV_in.len-16)));
}
if (sending){
std::cout << pack_out.Pack(true);
}else{
prebuffer << pack_out.Pack(true);
}
}
} }
} }

View file

@ -198,6 +198,13 @@ const char * DTSC::DTMI::Str(){return strval.c_str();};
/// If this object is not a container type, this function will always return 0. /// If this object is not a container type, this function will always return 0.
int DTSC::DTMI::hasContent(){return contents.size();}; int DTSC::DTMI::hasContent(){return contents.size();};
/// Returns true if this DTSC::DTMI value is non-default.
/// Non-default means it is either not a root element or has content.
bool DTSC::DTMI::isEmpty(){
if (myType != DTMI_ROOT){return false;}
return (hasContent() == 0);
};
/// Adds an DTSC::DTMI to this object. Works for all types, but only makes sense for container types. /// Adds an DTSC::DTMI to this object. Works for all types, but only makes sense for container types.
/// This function resets DTMI::packed to an empty string, forcing a repack on the next call to DTMI::Pack. /// This function resets DTMI::packed to an empty string, forcing a repack on the next call to DTMI::Pack.
/// If the indice name already exists, replaces the indice. /// If the indice name already exists, replaces the indice.
@ -213,9 +220,12 @@ void DTSC::DTMI::addContent(DTSC::DTMI c){
}; };
/// Returns a pointer to the object held at indice i. /// Returns a pointer to the object held at indice i.
/// Returns AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice. /// Returns null pointer if no object is held at this indice.
/// \param i The indice of the object in this container. /// \param i The indice of the object in this container.
DTSC::DTMI* DTSC::DTMI::getContentP(int i){return &contents.at(i);}; DTSC::DTMI* DTSC::DTMI::getContentP(int i){
if (contents.size() <= (unsigned int)i){return 0;}
return &contents.at(i);
};
/// Returns a copy of the object held at indice i. /// Returns a copy of the object held at indice i.
/// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice. /// Returns a AMF::AMF0_DDV_CONTAINER of indice "error" if no object is held at this indice.

View file

@ -62,6 +62,7 @@ namespace DTSC{
std::string & StrValue(); std::string & StrValue();
const char * Str(); const char * Str();
int hasContent(); int hasContent();
bool isEmpty();
void addContent(DTMI c); void addContent(DTMI c);
DTMI* getContentP(int i); DTMI* getContentP(int i);
DTMI getContent(int i); DTMI getContent(int i);

View file

@ -771,3 +771,178 @@ bool FLV::Tag::FileLoader(FILE * f){
fcntl(fileno(f), F_SETFL, preflags); fcntl(fileno(f), F_SETFL, preflags);
return false; return false;
}//FLV_GetPacket }//FLV_GetPacket
DTSC::DTMI FLV::Tag::toDTSC(DTSC::DTMI & metadata){
DTSC::DTMI pack_out; // Storage for outgoing DTMI data.
if (data[0] == 0x12){
AMF::Object meta_in = AMF::parse((unsigned char*)data+11, len-15);
if (meta_in.getContentP(0) && (meta_in.getContentP(0)->StrValue() == "onMetaData") && meta_in.getContentP(1)){
AMF::Object * tmp = meta_in.getContentP(1);
if (tmp->getContentP("videocodecid")){
switch ((unsigned int)tmp->getContentP("videocodecid")->NumValue()){
case 2: Meta_Put(metadata, "video", "codec", "H263"); break;
case 4: Meta_Put(metadata, "video", "codec", "VP6"); break;
case 7: Meta_Put(metadata, "video", "codec", "H264"); break;
default: Meta_Put(metadata, "video", "codec", "?"); break;
}
}
if (tmp->getContentP("audiocodecid")){
switch ((unsigned int)tmp->getContentP("audiocodecid")->NumValue()){
case 2: Meta_Put(metadata, "audio", "codec", "MP3"); break;
case 10: Meta_Put(metadata, "audio", "codec", "AAC"); break;
default: Meta_Put(metadata, "audio", "codec", "?"); break;
}
}
if (tmp->getContentP("width")){
Meta_Put(metadata, "video", "width", tmp->getContentP("width")->NumValue());
}
if (tmp->getContentP("height")){
Meta_Put(metadata, "video", "height", tmp->getContentP("height")->NumValue());
}
if (tmp->getContentP("framerate")){
Meta_Put(metadata, "video", "fpks", tmp->getContentP("framerate")->NumValue()*1000);
}
if (tmp->getContentP("videodatarate")){
Meta_Put(metadata, "video", "bps", (tmp->getContentP("videodatarate")->NumValue()*1024)/8);
}
if (tmp->getContentP("audiodatarate")){
Meta_Put(metadata, "audio", "bps", (tmp->getContentP("audiodatarate")->NumValue()*1024)/8);
}
if (tmp->getContentP("audiosamplerate")){
Meta_Put(metadata, "audio", "rate", tmp->getContentP("audiosamplerate")->NumValue());
}
if (tmp->getContentP("audiosamplesize")){
Meta_Put(metadata, "audio", "size", tmp->getContentP("audiosamplesize")->NumValue());
}
if (tmp->getContentP("stereo")){
if (tmp->getContentP("stereo")->NumValue() == 1){
Meta_Put(metadata, "audio", "channels", 2);
}else{
Meta_Put(metadata, "audio", "channels", 1);
}
}
}
return pack_out;//empty
}
if (data[0] == 0x08){
char audiodata = data[11];
if (needsInitData() && isInitData()){
if ((audiodata & 0xF0) == 0xA0){
Meta_Put(metadata, "audio", "init", std::string((char*)data+13, (size_t)len-17));
}else{
Meta_Put(metadata, "audio", "init", std::string((char*)data+12, (size_t)len-16));
}
return pack_out;//skip rest of parsing, get next tag.
}
pack_out = DTSC::DTMI("audio", DTSC::DTMI_ROOT);
pack_out.addContent(DTSC::DTMI("datatype", "audio"));
pack_out.addContent(DTSC::DTMI("time", tagTime()));
if (!Meta_Has(metadata, "audio", "codec")){
switch (audiodata & 0xF0){
case 0x20: Meta_Put(metadata, "audio", "codec", "MP3"); break;
case 0xA0: Meta_Put(metadata, "audio", "codec", "AAC"); break;
default: Meta_Put(metadata, "audio", "codec", "?"); break;
}
}
if (!Meta_Has(metadata, "audio", "rate")){
switch (audiodata & 0x0C){
case 0x0: Meta_Put(metadata, "audio", "rate", 5512); break;
case 0x4: Meta_Put(metadata, "audio", "rate", 11025); break;
case 0x8: Meta_Put(metadata, "audio", "rate", 22050); break;
case 0xC: Meta_Put(metadata, "audio", "rate", 44100); break;
}
}
if (!Meta_Has(metadata, "audio", "size")){
switch (audiodata & 0x02){
case 0x0: Meta_Put(metadata, "audio", "size", 8); break;
case 0x2: Meta_Put(metadata, "audio", "size", 16); break;
}
}
if (!Meta_Has(metadata, "audio", "channels")){
switch (audiodata & 0x01){
case 0x0: Meta_Put(metadata, "audio", "channels", 1); break;
case 0x1: Meta_Put(metadata, "audio", "channels", 2); break;
}
}
if ((audiodata & 0xF0) == 0xA0){
pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+13, (size_t)len-17)));
}else{
pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+12, (size_t)len-16)));
}
return pack_out;
}
if (data[0] == 0x09){
char videodata = data[11];
if (needsInitData() && isInitData()){
if ((videodata & 0x0F) == 7){
Meta_Put(metadata, "video", "init", std::string((char*)data+16, (size_t)len-20));
}else{
Meta_Put(metadata, "video", "init", std::string((char*)data+12, (size_t)len-16));
}
return pack_out;//skip rest of parsing, get next tag.
}
if (!Meta_Has(metadata, "video", "codec")){
switch (videodata & 0x0F){
case 2: Meta_Put(metadata, "video", "codec", "H263"); break;
case 4: Meta_Put(metadata, "video", "codec", "VP6"); break;
case 7: Meta_Put(metadata, "video", "codec", "H264"); break;
default: Meta_Put(metadata, "video", "codec", "?"); break;
}
}
pack_out = DTSC::DTMI("video", DTSC::DTMI_ROOT);
pack_out.addContent(DTSC::DTMI("datatype", "video"));
switch (videodata & 0xF0){
case 0x10: pack_out.addContent(DTSC::DTMI("keyframe", 1)); break;
case 0x20: pack_out.addContent(DTSC::DTMI("interframe", 1)); break;
case 0x30: pack_out.addContent(DTSC::DTMI("disposableframe", 1)); break;
case 0x40: pack_out.addContent(DTSC::DTMI("keyframe", 1)); break;
case 0x50: return DTSC::DTMI(); break;//the video info byte we just throw away - useless to us...
}
pack_out.addContent(DTSC::DTMI("time", tagTime()));
if ((videodata & 0x0F) == 7){
switch (data[12]){
case 1: pack_out.addContent(DTSC::DTMI("nalu", 1)); break;
case 2: pack_out.addContent(DTSC::DTMI("nalu_end", 1)); break;
}
int offset = (data[13] << 16) + (data[14] << 8) + data[15];
offset = (offset << 8) >> 8;
pack_out.addContent(DTSC::DTMI("offset", offset));
pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+16, (size_t)len-20)));
}else{
pack_out.addContent(DTSC::DTMI("data", std::string((char*)data+12, (size_t)len-16)));
}
return pack_out;
}
return pack_out;//should never get here
}//FLV::Tag::toDTSC
/// Inserts std::string type metadata into the passed DTMI object.
/// \arg meta The DTMI object to put the metadata into.
/// \arg cat Metadata category to insert into.
/// \arg elem Element name to put into the category.
/// \arg val Value to put into the element name.
void FLV::Tag::Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, std::string val){
if (meta.getContentP(cat) == 0){meta.addContent(DTSC::DTMI(cat));}
meta.getContentP(cat)->addContent(DTSC::DTMI(elem, val));
}
/// Inserts uint64_t type metadata into the passed DTMI object.
/// \arg meta The DTMI object to put the metadata into.
/// \arg cat Metadata category to insert into.
/// \arg elem Element name to put into the category.
/// \arg val Value to put into the element name.
void FLV::Tag::Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, uint64_t val){
if (meta.getContentP(cat) == 0){meta.addContent(DTSC::DTMI(cat));}
meta.getContentP(cat)->addContent(DTSC::DTMI(elem, val));
}
/// Returns true if the named category and elementname are available in the metadata.
/// \arg meta The DTMI object to check.
/// \arg cat Metadata category to check.
/// \arg elem Element name to check.
bool FLV::Tag::Meta_Has(DTSC::DTMI & meta, std::string cat, std::string elem){
if (meta.getContentP(cat) == 0){return false;}
if (meta.getContentP(cat)->getContentP(elem) == 0){return false;}
return true;
}

View file

@ -43,6 +43,7 @@ namespace FLV {
bool DTSCVideoInit(DTSC::Stream & S); bool DTSCVideoInit(DTSC::Stream & S);
bool DTSCAudioInit(DTSC::Stream & S); bool DTSCAudioInit(DTSC::Stream & S);
bool DTSCMetaInit(DTSC::Stream & S); bool DTSCMetaInit(DTSC::Stream & S);
DTSC::DTMI toDTSC(DTSC::DTMI & metadata);
bool MemLoader(char * D, unsigned int S, unsigned int & P); bool MemLoader(char * D, unsigned int S, unsigned int & P);
bool SockLoader(int sock); bool SockLoader(int sock);
bool SockLoader(Socket::Connection sock); bool SockLoader(Socket::Connection sock);
@ -56,6 +57,10 @@ namespace FLV {
bool MemReadUntil(char * buffer, unsigned int count, unsigned int & sofar, char * D, unsigned int S, unsigned int & P); bool MemReadUntil(char * buffer, unsigned int count, unsigned int & sofar, char * D, unsigned int S, unsigned int & P);
bool SockReadUntil(char * buffer, unsigned int count, unsigned int & sofar, Socket::Connection & sock); bool SockReadUntil(char * buffer, unsigned int count, unsigned int & sofar, Socket::Connection & sock);
bool FileReadUntil(char * buffer, unsigned int count, unsigned int & sofar, FILE * f); bool FileReadUntil(char * buffer, unsigned int count, unsigned int & sofar, FILE * f);
//DTSC writer helpers
void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, std::string val);
void Meta_Put(DTSC::DTMI & meta, std::string cat, std::string elem, uint64_t val);
bool Meta_Has(DTSC::DTMI & meta, std::string cat, std::string elem);
};//Tag };//Tag
};//FLV namespace };//FLV namespace