1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
/*
* audio.cpp: A program for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
* $Id$
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "audio.h"
cAudio::cAudio(cDecoder *decoderParam, cIndex *indexParam, cCriteria *criteriaParam) {
decoder = decoderParam;
index = indexParam;
criteria = criteriaParam;
}
cAudio::~cAudio() {
ResetMarks();
}
void cAudio::ResetMarks() {
audioMarks = {};
}
void cAudio::AddMark(int type, const int packetNumber, const int64_t framePTS, const int channelsBefore, const int channelsAfter) {
if (audioMarks.Count >= audioMarks.maxCount) { // array start with 0
esyslog("cAudio::AddMark(): too much audio marks %d at once detected", audioMarks.Count);
return;
}
audioMarks.Number[audioMarks.Count].position = packetNumber;
audioMarks.Number[audioMarks.Count].framePTS = framePTS;
audioMarks.Number[audioMarks.Count].type = type;
audioMarks.Number[audioMarks.Count].channelsBefore = channelsBefore;
audioMarks.Number[audioMarks.Count].channelsAfter = channelsAfter;
audioMarks.Count++;
}
void cAudio::Silence() {
int normVolume = decoder->GetVolume();
if (normVolume < 0) return; // no valid volume
// set start/end, with audio packets there is packet PTS the same as frame PTS
if ((normVolume == 0) && (audioMP2Silence.startAudioPTS < 0)) {
audioMP2Silence.startAudioPTS = decoder->GetPacketPTS(); // start of silence
#ifdef DEBUG_VOLUME
dsyslog("cAudio::Silence(): packet (%d): start silence at audio PTS %ld detected", decoder->GetPacketNumber(), audioMP2Silence.startAudioPTS);
#endif
}
if ((normVolume >= MIN_NONSILENCE_VOLUME) && (audioMP2Silence.startAudioPTS >= 0) && (audioMP2Silence.stopAudioPTS < 0)) {
audioMP2Silence.stopAudioPTS = decoder->GetPacketPTS(); // end of silence
#ifdef DEBUG_VOLUME
dsyslog("cAudio::Silence(): packet (%d): stop silence at audio PTS %ld detected", decoder->GetPacketNumber(), audioMP2Silence.stopAudioPTS);
#endif
}
// get nearesr video packet number and PTS
if ((audioMP2Silence.startAudioPTS >= 0) && (audioMP2Silence.startPacketNumber < 0)) audioMP2Silence.startPacketNumber = index->GetPacketNumberBeforePTS(audioMP2Silence.startAudioPTS, &audioMP2Silence.startVideoPTS);
if ((audioMP2Silence.stopAudioPTS >= 0) && (audioMP2Silence.stopPacketNumber < 0)) audioMP2Silence.stopPacketNumber = index->GetPacketNumberAfterPTS(audioMP2Silence.stopAudioPTS, &audioMP2Silence.stopVideoPTS);
// return result
if ((audioMP2Silence.startPacketNumber >= 0) && (audioMP2Silence.stopPacketNumber >= 0)) { // silence ready, can be processed
#ifdef DEBUG_VOLUME
dsyslog("cAudio::Silence(): packet (%d): start: packet (%d), audio PIS %ld, video PTS %ld", decoder->GetPacketNumber(), audioMP2Silence.startPacketNumber, audioMP2Silence.startAudioPTS, audioMP2Silence.startVideoPTS);
dsyslog("cAudio::Silence(): packet (%d): stop: packet (%d), audio PIS %ld, video PTS %ld", decoder->GetPacketNumber(), audioMP2Silence.stopPacketNumber, audioMP2Silence.stopAudioPTS, audioMP2Silence.stopVideoPTS);
#endif
// very short silence with can result in reversed start/stop video packet numbers becaue of negativ PTS offset
// swap start/stop position to fix that, don't care on position, for mark position we use PTS
if (audioMP2Silence.startPacketNumber > audioMP2Silence.stopPacketNumber) {
dsyslog("cAudio::Silence(): start (%d) > stop (%d), swap position", audioMP2Silence.startPacketNumber, audioMP2Silence.stopPacketNumber);
std::swap(audioMP2Silence.startPacketNumber, audioMP2Silence.stopPacketNumber);
}
// add marks
AddMark(MT_SOUNDSTOP, audioMP2Silence.startPacketNumber, audioMP2Silence.startVideoPTS, 0, 0);
AddMark(MT_SOUNDSTART, audioMP2Silence.stopPacketNumber, audioMP2Silence.stopVideoPTS, 0, 0);
// reset all values
audioMP2Silence.startPacketNumber = -1;
audioMP2Silence.startAudioPTS = -1;
audioMP2Silence.startVideoPTS = -1;
audioMP2Silence.stopPacketNumber = -1;
audioMP2Silence.stopAudioPTS = -1;
audioMP2Silence.stopVideoPTS = -1;
}
return;
}
void cAudio::ChannelChange() {
// check channel change
sAudioAC3Channels *channelChange = decoder->GetChannelChange(); // check channel change
if (channelChange) { // we have unprocessed channel change
dsyslog("cAudio::ChannelChange(): packet (%d) PTS %" PRId64 ": AC3 audio stream changed channel from %d to %d", channelChange->videoPacketNumber, channelChange->videoFramePTS, channelChange->channelCountBefore, channelChange->channelCountAfter);
if (channelChange->channelCountAfter == 2) AddMark(MT_CHANNELSTOP, channelChange->videoPacketNumber, channelChange->videoFramePTS, channelChange->channelCountBefore, channelChange->channelCountAfter);
else if ((channelChange->channelCountBefore == 2) && // ignore channel change from 5 to 6 or from 6 to 5
((channelChange->channelCountAfter == 5) || (channelChange->channelCountAfter == 6))) AddMark(MT_CHANNELSTART, channelChange->videoPacketNumber, channelChange->videoFramePTS, channelChange->channelCountBefore, channelChange->channelCountAfter);
else dsyslog("cAudio::Process(): ignore channel count change from %d to %d", channelChange->channelCountBefore, channelChange->channelCountAfter);
channelChange->channelCountBefore = channelChange->channelCountAfter;
channelChange->processed = true;
}
}
sMarkAdMarks *cAudio::Detect() {
ResetMarks();
// do audio based checks
if (criteria->GetDetectionState(MT_CHANNELCHANGE)) ChannelChange();
if (criteria->GetDetectionState(MT_SOUNDCHANGE)) Silence();
// return list of new marks
if (audioMarks.Count > 0) {
return &audioMarks;
}
return nullptr;
}
|