summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to 'misc')
-rw-r--r--misc/avdetector.cpp250
-rw-r--r--misc/avdetector.h82
-rw-r--r--misc/util.cpp44
-rw-r--r--misc/util.h2
4 files changed, 346 insertions, 32 deletions
diff --git a/misc/avdetector.cpp b/misc/avdetector.cpp
index 8f3bc8f..bb1c9c8 100644
--- a/misc/avdetector.cpp
+++ b/misc/avdetector.cpp
@@ -6,31 +6,207 @@
*/
#include "avdetector.h"
-extern "C" {
-#include <libavformat/avformat.h>
-#include <libavcodec/avcodec.h>
+#include <sys/stat.h>
+
+cAudioVideoDetector::cAudioVideoDetector(const char* Filename) : mResourceType(UPNP_RESOURCE_FILE) {
+ this->mResource.Filename = Filename;
+ this->init();
}
-using namespace std;
+cAudioVideoDetector::cAudioVideoDetector(const cChannel* Channel) : mResourceType(UPNP_RESOURCE_CHANNEL) {
+ this->mResource.Channel = Channel;
+ this->init();
+}
-int cAudioVideoDetector::detectVideoProperties(cUPnPResource* Resource, const char* Filename){
-// // Register avformat
+cAudioVideoDetector::cAudioVideoDetector(const cRecording* Recording) : mResourceType(UPNP_RESOURCE_RECORDING) {
+ this->mResource.Recording = Recording;
+ this->init();
+}
+
+cAudioVideoDetector::~cAudioVideoDetector(){
+ this->uninit();
+}
+
+void cAudioVideoDetector::init(){
+ this->mBitrate = 0;
+ this->mBitsPerSample = 0;
+ this->mColorDepth = 0;
+ this->mDLNAProfile = NULL;
+ this->mDuration = 0;
+ this->mHeight = 0;
+ this->mNrAudioChannels = 0;
+ this->mSampleFrequency = 0;
+ this->mSize = 0;
+ this->mWidth = 0;
+}
+
+void cAudioVideoDetector::uninit(){
+ this->init();
+}
+
+int cAudioVideoDetector::detectProperties(){
+ int ret = 0;
+ switch(this->mResourceType){
+ case UPNP_RESOURCE_CHANNEL:
+ ret = this->detectChannelProperties();
+ break;
+ case UPNP_RESOURCE_RECORDING:
+ ret = this->detectRecordingProperties();
+ break;
+ case UPNP_RESOURCE_FILE:
+ ret = this->detectFileProperties();
+ break;
+ default:
+ WARNING("This resource type is not yet implemented.");
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+int cAudioVideoDetector::detectChannelProperties(){
+ this->mBitrate = 0;
+ this->mBitsPerSample = 0;
+ this->mColorDepth = 0;
+ this->mDuration = 0;
+ this->mHeight = 0;
+ this->mNrAudioChannels = 0;
+ this->mSampleFrequency = 0;
+ this->mSize = (off64_t)-1;
+ this->mWidth = 0;
+
+ switch(this->mResource.Channel->Vtype()){
+ case 0x02:
+ // MPEG2 Video
+ this->mDLNAProfile = &DLNA_PROFILE_MPEG_TS_SD_EU_ISO;
+ break;
+ case 0x1B:
+ this->mDLNAProfile = &DLNA_PROFILE_AVC_TS_HD_EU_ISO;
+ break;
+ default:
+ ERROR("Unknown video type %d for channel %s!", this->mResource.Channel->Vtype(), this->mResource.Channel->Name());
+ this->mDLNAProfile = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int cAudioVideoDetector::detectRecordingProperties(){
+
+ if(this->mResource.Recording->IsPesRecording()){
+ ERROR("Sorry, PES Recordings are not supported");
+ return -1;
+ }
+
+ int ret = 0;
+ AVFormatContext *FormatCtx = NULL;
+
+ cIndexFile* Index = new cIndexFile(this->mResource.Recording->FileName(), false, this->mResource.Recording->IsPesRecording());
+ cFileName* RecFile = new cFileName(this->mResource.Recording->FileName(), false, false, this->mResource.Recording->IsPesRecording());
+ if(Index && Index->Ok()){
+ this->mDuration = (off64_t) (Index->Last() * AVDETECTOR_TIME_BASE / SecondsToFrames(1, this->mResource.Recording->FramesPerSecond()));
+ MESSAGE(VERBOSE_METADATA,"Record length: %llds", this->mDuration);
+
+ uint16_t FileNumber = 0;
+ off_t FileOffset = 0;
+
+ if(Index->Get(Index->Last()-1, &FileNumber, &FileOffset))
+ for(int i = 0; i < FileNumber; i++){
+ struct stat Stats;
+ RecFile->SetOffset(i+1);
+ stat(RecFile->Name(),&Stats);
+ this->mSize += (off64_t) Stats.st_size;
+ }
+
+ av_register_all();
+
+ if(!(ret = av_open_input_file(&FormatCtx, RecFile->Name(), NULL, 0, NULL))){
+ if((ret = av_find_stream_info(FormatCtx))<0){
+ ERROR("AVDetector: Cannot find the stream information");
+ }
+ else {
+ if((ret = this->analyseVideo(FormatCtx))<0){
+ ERROR("AVDetector: Error while analysing video");
+ }
+ if((ret = this->analyseAudio(FormatCtx))<0){
+ ERROR("AVDetector: Error while analysing audio");
+ }
+ }
+ }
+ }
+ else {
+ ret = -1;
+ }
+
+ if(ret != 0){
+ ERROR("Error occured while detecting properties");
+ }
+
+ delete RecFile;
+ delete Index;
+ av_free(FormatCtx);
+
+ return ret;
+}
+
+int cAudioVideoDetector::detectFileProperties(){
av_register_all();
+ int ret = 0;
+
AVFormatContext *FormatCtx = NULL;
- if(av_open_input_file(&FormatCtx, Filename, NULL, 0, NULL)){
- ERROR("AVDetector: Error while opening file %s", Filename);
+
+ if(av_open_input_file(&FormatCtx, this->mResource.Filename, NULL, 0, NULL)){
+ ERROR("AVDetector: Error while opening file %s", this->mResource.Filename);
return -1;
}
+ else {
+ if(av_find_stream_info(FormatCtx)<0){
+ ERROR("AVDetector: Cannot find the stream information");
+ return -1;
+ }
+ else {
- if(av_find_stream_info(FormatCtx)<0){
- ERROR("AVDetector: Cannot find the stream information");
- return -1;
+ if((ret = this->analyseFormat(FormatCtx))<0){
+ ERROR("AVDetector: Error while analysing format");
+ return ret;
+ }
+ if((ret = this->analyseVideo(FormatCtx))<0){
+ ERROR("AVDetector: Error while analysing video");
+ return ret;
+ }
+ if((ret = this->analyseAudio(FormatCtx))<0){
+ ERROR("AVDetector: Error while analysing audio");
+ return ret;
+ }
+
+ return 0;
+ }
}
+}
-#ifdef DEBUG
- dump_format(FormatCtx, 0, Filename, 0);
-#endif
+int cAudioVideoDetector::analyseFormat(AVFormatContext* FormatCtx){
+ if(!FormatCtx) return -1;
+
+ this->mSize = FormatCtx->file_size;
+ this->mDuration = FormatCtx->duration;
+
+ MESSAGE(VERBOSE_METADATA, "Format properties: %lld and %lld Bytes", this->mDuration, this->mSize);
+
+ AVMetadataTag* Tag = NULL;
+
+ while((Tag=av_metadata_get(FormatCtx->metadata,"",Tag,AV_METADATA_IGNORE_SUFFIX))){
+ MESSAGE(VERBOSE_METADATA, "%s: %s", Tag->key, Tag->value);
+ }
+
+ return 0;
+}
+
+int cAudioVideoDetector::analyseVideo(AVFormatContext* FormatCtx)
+{
+// // Register avformat
unsigned int i; int videoStream = -1;
@@ -43,24 +219,52 @@ int cAudioVideoDetector::detectVideoProperties(cUPnPResource* Resource, const ch
}
if(videoStream == -1){
ERROR("AVDetector: No video stream found");
- return -1;
+ return 1;
}
CodecCtx = FormatCtx->streams[videoStream]->codec;
AVCodec* Codec = avcodec_find_decoder(CodecCtx->codec_id);
- unsigned int width = CodecCtx->width;
- unsigned int height = CodecCtx->height;
- unsigned int bitrate = CodecCtx->bit_rate;
+ this->mWidth = CodecCtx->width;
+ this->mHeight = CodecCtx->height;
+ this->mBitrate = CodecCtx->bit_rate;
+ this->mSampleFrequency = CodecCtx->sample_rate;
+ this->mBitsPerSample = CodecCtx->bits_per_raw_sample;
+
+ // TODO: what's the color depth of the stream
+
const char* codecName = (Codec)?Codec->name:"unknown";
- MESSAGE(VERBOSE_METADATA, "AVDetector: %s-stream %dx%d at %d bit/s", codecName, width, height, bitrate);
+ MESSAGE(VERBOSE_METADATA, "AVDetector: %s-stream %dx%d at %d bit/s", codecName, this->mWidth, this->mHeight, this->mBitrate);
+ return 0;
+}
- Resource->mBitrate = bitrate;
- Resource->mSampleFrequency = CodecCtx->sample_rate;
- Resource->mResolution = cString::sprintf("%dx%d", width, height);
-
+int cAudioVideoDetector::analyseAudio(AVFormatContext* FormatCtx){
+
+ unsigned int i; int audioStream = -1;
+
+ AVCodecContext *CodecCtx = NULL;
+ for(i = 0; i < FormatCtx->nb_streams; i++){
+ if(FormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO){
+ audioStream = i;
+ break;
+ }
+ }
+ if(audioStream == -1){
+ ERROR("AVDetector: No audio stream found");
+ return 1;
+ }
+
+ CodecCtx = FormatCtx->streams[audioStream]->codec;
+ AVCodec* Codec = avcodec_find_decoder(CodecCtx->codec_id);
+
+ this->mNrAudioChannels = CodecCtx->channels;
+
+ const char* codecName = (Codec)?Codec->name:"unknown";
+
+ MESSAGE(VERBOSE_METADATA, "AVDetector: %s-stream at %d bit/s", codecName, CodecCtx->bit_rate);
return 0;
}
+
diff --git a/misc/avdetector.h b/misc/avdetector.h
index b043c59..33b3298 100644
--- a/misc/avdetector.h
+++ b/misc/avdetector.h
@@ -9,6 +9,13 @@
#define _AVDETECTOR_H
#include "../database/object.h"
+#include <vdr/recording.h>
+#include <vdr/channels.h>
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+}
/**
* The audio/video detector
@@ -18,23 +25,80 @@
* required for determination of a suitable DLNA profile.
*/
class cAudioVideoDetector {
-public:
- cAudioVideoDetector(){};
- virtual ~cAudioVideoDetector(){};
+private:
+ void init();
+ void uninit();
+ int detectChannelProperties();
+ int detectFileProperties();
+ int detectRecordingProperties();
/**
* Detect video properties
*
- * This detects video properties of a video stream and stores them in the
- * Resource object.
+ * This detects video properties of a video stream
*
- * @param Resource the resource, where to save the data
- * @param Filename the file, which shall be read
* @return returns
* - \bc 0, if the detection was successful
* - \bc <0, otherwise
*/
- int detectVideoProperties(cUPnPResource* Resource, const char* Filename);
-private:
+ int analyseVideo(AVFormatContext* FormatCtx);
+ /**
+ * Detect audio properties
+ *
+ * This detects audio properties of a video or audio stream
+ *
+ * @return returns
+ * - \bc 0, if the detection was successful
+ * - \bc <0, otherwise
+ */
+ int analyseAudio(AVFormatContext* FormatCtx);
+ int analyseFormat(AVFormatContext* FormatCtx);
+ int detectDLNAProfile();
+ UPNP_RESOURCE_TYPES mResourceType;
+ union {
+ const cChannel* Channel;
+ const cRecording* Recording;
+ const char* Filename;
+ } mResource;
+ int mWidth;
+ int mHeight;
+ int mBitrate;
+ int mBitsPerSample;
+ int mColorDepth;
+ off64_t mDuration;
+ off64_t mSize;
+ int mSampleFrequency;
+ int mNrAudioChannels;
+ DLNAProfile* mDLNAProfile;
+public:
+ cAudioVideoDetector(const char* Filename);
+ cAudioVideoDetector(const cChannel* Channel);
+ cAudioVideoDetector(const cRecording* Recording);
+ virtual ~cAudioVideoDetector();
+ /**
+ * Detect resource properties of the file
+ *
+ * This detects the resource properties of a file. If the returned value
+ * is 0, no erros occured while detection and the properties are properly
+ * set. Otherwise, in case of an error, the properties may have
+ * unpredictable values.
+ *
+ * @return returns
+ * - \bc 0, if the detection was successful
+ * - \bc <0, otherwise
+ */
+ int detectProperties();
+ DLNAProfile* getDLNAProfile() const { return this->mDLNAProfile; }
+ const char* getContentType() const { return (this->mDLNAProfile) ? this->mDLNAProfile->mime : NULL; }
+ const char* getProtocolInfo() const;
+ int getWidth() const { return this->mWidth; }
+ int getHeight() const { return this->mHeight; }
+ int getBitrate() const { return this->mBitrate; }
+ int getBitsPerSample() const { return this->mBitsPerSample; }
+ int getSampleFrequency() const { return this->mSampleFrequency; }
+ int getNumberOfAudioChannels() const { return this->mNrAudioChannels; }
+ int getColorDepth() const { return this->mColorDepth; }
+ off64_t getFileSize() const { return this->mSize; }
+ off64_t getDuration() const { return this->mDuration; }
};
#endif /* _AVDETECTOR_H */
diff --git a/misc/util.cpp b/misc/util.cpp
index 8cfc524..d93d027 100644
--- a/misc/util.cpp
+++ b/misc/util.cpp
@@ -16,6 +16,50 @@
#include <upnp/ixml.h>
#include <arpa/inet.h>
#include <iosfwd>
+#include <time.h>
+
+#define DURATION_MAX_STRING_LENGTH 13 // DLNA: 1-5 DIGIT hours :
+ // 2 DIGIT minutes :
+ // 2 DIGIT seconds .
+ // 3 DIGIT fraction
+
+char* duration(off64_t duration, unsigned int timeBase){
+ if (timeBase == 0) timeBase = 1;
+
+ int seconds, minutes, hours, fraction;
+
+ seconds = duration / timeBase;
+ fraction = duration % timeBase;
+ minutes = seconds / 60;
+ seconds %= 60;
+ hours = minutes / 60;
+ minutes %= 60;
+
+ char* output = new char[DURATION_MAX_STRING_LENGTH];
+
+ if(!snprintf(
+ output,
+ DURATION_MAX_STRING_LENGTH,
+ UPNP_DURATION_FORMAT_STRING,
+ hours, minutes, seconds)
+ ){
+ delete output;
+ return NULL;
+ }
+ else {
+ if(timeBase > 1 &&
+ !snprintf(
+ output,
+ DURATION_MAX_STRING_LENGTH,
+ "%s" UPNP_DURATION_FRAME_FORMAT,
+ output, fraction)
+ ){
+ delete output;
+ return NULL;
+ }
+ else return output;
+ }
+}
char* substr(const char* str, unsigned int offset, unsigned int length){
if(offset > strlen(str)) return NULL;
diff --git a/misc/util.h b/misc/util.h
index 6ff2a54..e5bc061 100644
--- a/misc/util.h
+++ b/misc/util.h
@@ -105,6 +105,8 @@ int ixmlAddProperty(IN IXML_Document* document, IN IXML_Element* node, const cha
* @param length the length of the new string
*/
char* substr(const char* str, unsigned int offset, unsigned int length);
+
+char* duration(off64_t duration, unsigned int timeBase = 1);
#if 0
{
#endif