Enable aac writer and use resmpling for some AAC streams thx Taapat and technik

This commit is contained in:
schpuntik
2016-10-28 23:42:58 +02:00
parent 19b576a45c
commit 73483990f8
7 changed files with 116 additions and 73 deletions

View File

@@ -49,7 +49,7 @@ class Output
int audiofd; int audiofd;
Writer *videoWriter, *audioWriter; Writer *videoWriter, *audioWriter;
Mutex audioMutex, videoMutex; Mutex audioMutex, videoMutex;
AVStream *audioStream, *videoStream; Track *audioTrack, *videoTrack;
Player *player; Player *player;
public: public:
Output(); Output();
@@ -70,8 +70,8 @@ class Output
bool ClearVideo(); bool ClearVideo();
bool GetPts(int64_t &pts); bool GetPts(int64_t &pts);
bool GetFrameCount(int64_t &framecount); bool GetFrameCount(int64_t &framecount);
bool SwitchAudio(AVStream *stream); bool SwitchAudio(Track *track);
bool SwitchVideo(AVStream *stream); bool SwitchVideo(Track *track);
bool Write(AVStream *stream, AVPacket *packet, int64_t Pts); bool Write(AVStream *stream, AVPacket *packet, int64_t Pts);
}; };

View File

@@ -49,7 +49,7 @@ class Writer
static void Register(Writer *w, enum AVCodecID id, audio_encoding_t encoding); static void Register(Writer *w, enum AVCodecID id, audio_encoding_t encoding);
static video_encoding_t GetVideoEncoding(enum AVCodecID id); static video_encoding_t GetVideoEncoding(enum AVCodecID id);
static audio_encoding_t GetAudioEncoding(enum AVCodecID id); static audio_encoding_t GetAudioEncoding(enum AVCodecID id);
static Writer *GetWriter(enum AVCodecID id, enum AVMediaType codec_type); static Writer *GetWriter(enum AVCodecID id, enum AVMediaType codec_type, int track_type);
virtual void Init(int _fd, AVStream * /*stream*/, Player *_player ) { fd = _fd; player = _player; } virtual void Init(int _fd, AVStream * /*stream*/, Player *_player ) { fd = _fd; player = _player; }
virtual bool Write(AVPacket *packet, int64_t pts); virtual bool Write(AVPacket *packet, int64_t pts);

View File

@@ -215,7 +215,7 @@ bool Input::Play()
if (_videoTrack && (_videoTrack->stream == stream)) { if (_videoTrack && (_videoTrack->stream == stream)) {
int64_t pts = calcPts(stream, packet.pts); int64_t pts = calcPts(stream, packet.pts);
if (audioSeen && !player->output.Write(stream, &packet, pts)) if (audioSeen && !player->output.Write(stream, &packet, pts))
logprintf("writing data to %s device failed\n", "video"); logprintf("writing data to video device failed\n");
} else if (_audioTrack && (_audioTrack->stream == stream)) { } else if (_audioTrack && (_audioTrack->stream == stream)) {
if (restart_audio_resampling) { if (restart_audio_resampling) {
restart_audio_resampling = false; restart_audio_resampling = false;
@@ -224,7 +224,7 @@ bool Input::Play()
if (!player->isBackWard) { if (!player->isBackWard) {
int64_t pts = calcPts(stream, packet.pts); int64_t pts = calcPts(stream, packet.pts);
if (!player->output.Write(stream, &packet, _videoTrack ? pts : 0)) if (!player->output.Write(stream, &packet, _videoTrack ? pts : 0))
logprintf("writing data to %s device failed\n", "audio"); logprintf("writing data to audio device failed\n");
} }
audioSeen = true; audioSeen = true;
} else if (_subtitleTrack && (_subtitleTrack->stream == stream)) { } else if (_subtitleTrack && (_subtitleTrack->stream == stream)) {
@@ -493,9 +493,9 @@ again:
} }
if (videoTrack) if (videoTrack)
player->output.SwitchVideo(videoTrack->stream); player->output.SwitchVideo(videoTrack);
if (audioTrack) if (audioTrack)
player->output.SwitchAudio(audioTrack->stream); player->output.SwitchAudio(audioTrack);
ReadSubtitles(filename); ReadSubtitles(filename);
@@ -544,6 +544,7 @@ bool Input::UpdateTracks()
} }
track.pid = use_index_as_pid ? n + 1: stream->id; track.pid = use_index_as_pid ? n + 1: stream->id;
track.ac3flags = 0;
switch (stream->codec->codec_type) { switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_VIDEO:
@@ -553,26 +554,43 @@ bool Input::UpdateTracks()
break; break;
case AVMEDIA_TYPE_AUDIO: case AVMEDIA_TYPE_AUDIO:
switch(stream->codec->codec_id) { switch(stream->codec->codec_id) {
case AV_CODEC_ID_MP2: case AV_CODEC_ID_MP2:
track.ac3flags = 9; track.ac3flags = 1;
break; break;
case AV_CODEC_ID_MP3: case AV_CODEC_ID_MP3:
track.ac3flags = 4; track.ac3flags = 2;
break; break;
case AV_CODEC_ID_AC3: case AV_CODEC_ID_AC3:
track.ac3flags = 1; track.ac3flags = 3;
break; break;
case AV_CODEC_ID_EAC3: case AV_CODEC_ID_DTS:
track.ac3flags = 7; track.ac3flags = 4;
break; break;
case AV_CODEC_ID_DTS: case AV_CODEC_ID_AAC: {
track.ac3flags = 6; unsigned int extradata_size = stream->codec->extradata_size;
break; unsigned int object_type = 2;
case AV_CODEC_ID_AAC: if(extradata_size >= 2)
track.ac3flags = 5; object_type = stream->codec->extradata[0] >> 3;
break; if (extradata_size <= 1 || object_type == 1 || object_type == 5) {
fprintf(stderr, "use resampling for AAC\n");
track.ac3flags = 6;
}
else
track.ac3flags = 5;
break;
}
case AV_CODEC_ID_FLAC:
track.ac3flags = 8;
break;
case AV_CODEC_ID_WMAV1:
case AV_CODEC_ID_WMAV2:
case AV_CODEC_ID_WMAVOICE:
case AV_CODEC_ID_WMAPRO:
case AV_CODEC_ID_WMALOSSLESS:
track.ac3flags = 9;
break;
default: default:
track.ac3flags = 0; track.ac3flags = 0;
} }
player->manager.addAudioTrack(track); player->manager.addAudioTrack(track);
if (!audioTrack) if (!audioTrack)
@@ -686,7 +704,7 @@ bool Input::GetDuration(int64_t &duration)
bool Input::SwitchAudio(Track *track) bool Input::SwitchAudio(Track *track)
{ {
audioTrack = track; audioTrack = track;
player->output.SwitchAudio(track ? track->stream : NULL); player->output.SwitchAudio(track ? track : NULL);
// player->Seek(-5000, false); // player->Seek(-5000, false);
return true; return true;
} }
@@ -706,7 +724,7 @@ bool Input::SwitchTeletext(Track *track)
bool Input::SwitchVideo(Track *track) bool Input::SwitchVideo(Track *track)
{ {
videoTrack = track; videoTrack = track;
player->output.SwitchVideo(track ? track->stream : NULL); player->output.SwitchVideo(track ? track : NULL);
return true; return true;
} }

View File

@@ -58,7 +58,7 @@ Output::Output()
{ {
videofd = audiofd = -1; videofd = audiofd = -1;
videoWriter = audioWriter = NULL; videoWriter = audioWriter = NULL;
videoStream = audioStream = NULL; videoTrack = audioTrack = NULL;
} }
Output::~Output() Output::~Output()
@@ -114,8 +114,8 @@ bool Output::Close()
audiofd = -1; audiofd = -1;
} }
videoStream = NULL; videoTrack = NULL;
audioStream = NULL; audioTrack = NULL;
return true; return true;
} }
@@ -129,18 +129,21 @@ bool Output::Play()
AVCodecContext *avcc; AVCodecContext *avcc;
if (videoStream && videofd > -1 && (avcc = videoStream->codec)) { if (videoTrack && videoTrack->stream && videofd > -1 && (avcc = videoTrack->stream->codec)) {
videoWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type); videoWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type, videoTrack->ac3flags);
videoWriter->Init(videofd, videoStream, player); videoWriter->Init(videofd, videoTrack->stream, player);
if (dioctl(videofd, VIDEO_SET_ENCODING, videoWriter->GetVideoEncoding(avcc->codec_id)) if (dioctl(videofd, VIDEO_SET_ENCODING, videoWriter->GetVideoEncoding(avcc->codec_id))
|| dioctl(videofd, VIDEO_PLAY, NULL)) || dioctl(videofd, VIDEO_PLAY, NULL))
ret = false; ret = false;
} }
if (audioStream && audiofd > -1 && (avcc = audioStream->codec)) { if (audioTrack && audioTrack->stream && audiofd > -1 && (avcc = audioTrack->stream->codec)) {
audioWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type); audioWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type, audioTrack->ac3flags);
audioWriter->Init(audiofd, audioStream, player); audioWriter->Init(audiofd, audioTrack->stream, player);
if (dioctl(audiofd, AUDIO_SET_ENCODING, audioWriter->GetAudioEncoding(avcc->codec_id)) audio_encoding_t audioEncoding = AUDIO_ENCODING_LPCMA;
if (audioTrack->ac3flags != 6)
audioEncoding = audioWriter->GetAudioEncoding(avcc->codec_id);
if (dioctl(audiofd, AUDIO_SET_ENCODING, audioEncoding)
|| dioctl(audiofd, AUDIO_PLAY, NULL)) || dioctl(audiofd, AUDIO_PLAY, NULL))
ret = false; ret = false;
} }
@@ -297,46 +300,49 @@ bool Output::GetFrameCount(int64_t &framecount)
return false; return false;
} }
bool Output::SwitchAudio(AVStream *stream) bool Output::SwitchAudio(Track *track)
{ {
ScopedLock a_lock(audioMutex); ScopedLock a_lock(audioMutex);
if (stream == audioStream) if (audioTrack && track->stream == audioTrack->stream)
return true; return true;
if (audiofd > -1) { if (audiofd > -1) {
dioctl(audiofd, AUDIO_STOP, NULL); dioctl(audiofd, AUDIO_STOP, NULL);
ioctl(audiofd, AUDIO_CLEAR_BUFFER, NULL); ioctl(audiofd, AUDIO_CLEAR_BUFFER, NULL);
} }
audioStream = stream; audioTrack = track;
if (stream) { if (track->stream) {
AVCodecContext *avcc = stream->codec; AVCodecContext *avcc = track->stream->codec;
if (!avcc) if (!avcc)
return false; return false;
audioWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type); audioWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type, audioTrack->ac3flags);
audioWriter->Init(audiofd, audioStream, player); audioWriter->Init(audiofd, audioTrack->stream, player);
if (audiofd > -1) { if (audiofd > -1) {
dioctl(audiofd, AUDIO_SET_ENCODING, Writer::GetAudioEncoding(avcc->codec_id)); audio_encoding_t audioEncoding = AUDIO_ENCODING_LPCMA;
if (audioTrack->ac3flags != 6)
audioEncoding = Writer::GetAudioEncoding(avcc->codec_id);
dioctl(audiofd, AUDIO_SET_ENCODING, audioEncoding);
dioctl(audiofd, AUDIO_PLAY, NULL); dioctl(audiofd, AUDIO_PLAY, NULL);
} }
} }
return true; return true;
} }
bool Output::SwitchVideo(AVStream *stream) bool Output::SwitchVideo(Track *track)
{ {
ScopedLock v_lock(videoMutex); ScopedLock v_lock(videoMutex);
if (stream == videoStream) if (videoTrack && track->stream == videoTrack->stream)
return true; return true;
if (videofd > -1) { if (videofd > -1) {
dioctl(videofd, VIDEO_STOP, NULL); dioctl(videofd, VIDEO_STOP, NULL);
ioctl(videofd, VIDEO_CLEAR_BUFFER, NULL); ioctl(videofd, VIDEO_CLEAR_BUFFER, NULL);
} }
videoStream = stream; videoTrack = track;
if (stream) { if (track->stream) {
AVCodecContext *avcc = stream->codec; AVCodecContext *avcc = track->stream->codec;
if (!avcc) if (!avcc)
return false; return false;
videoWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type); videoWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type, videoTrack->type);
videoWriter->Init(videofd, videoStream, player); videoWriter->Init(videofd, videoTrack->stream, player);
if (videofd > -1) { if (videofd > -1) {
dioctl(videofd, VIDEO_SET_ENCODING, Writer::GetVideoEncoding(avcc->codec_id)); dioctl(videofd, VIDEO_SET_ENCODING, Writer::GetVideoEncoding(avcc->codec_id));
dioctl(videofd, VIDEO_PLAY, NULL); dioctl(videofd, VIDEO_PLAY, NULL);

View File

@@ -242,27 +242,36 @@ bool WriterPCM::Write(AVPacket *packet, int64_t pts)
restart_audio_resampling = false; restart_audio_resampling = false;
initialHeader = true; initialHeader = true;
if (swr) {
swr_free(&swr); swr_free(&swr);
swr = NULL;
}
if (decoded_frame) {
av_frame_free(&decoded_frame);
decoded_frame = NULL;
}
AVCodec *codec = avcodec_find_decoder(c->codec_id); AVCodec *codec = avcodec_find_decoder(c->codec_id);
if (!codec) { if (!codec) {
fprintf(stderr, "%s %d: avcodec_find_decoder(%llx)\n", __func__, __LINE__, (unsigned long long) c->codec_id); fprintf(stderr, "%s %d: avcodec_find_decoder(%llx)\n", __func__, __LINE__, (unsigned long long) c->codec_id);
return false; return false;
} }
avcodec_close(c); avcodec_close(c);
if (avcodec_open2(c, codec, NULL)) { if (avcodec_open2(c, codec, NULL)) {
fprintf(stderr, "%s %d: avcodec_open2 failed\n", __func__, __LINE__); fprintf(stderr, "%s %d: avcodec_open2 failed\n", __func__, __LINE__);
return false; return false;
} }
} }
if (!swr) { if (!swr) {
int rates[] = { 48000, 96000, 192000, 44100, 88200, 176400, 0 };
int *rate = rates;
int in_rate = c->sample_rate; int in_rate = c->sample_rate;
while (*rate && ((*rate / in_rate) * in_rate != *rate) && (in_rate / *rate) * *rate != in_rate) // rates in descending order
rate++; int rates[] = {192000, 176400, 96000, 88200, 48000, 44100, 0};
out_sample_rate = *rate ? *rate : 44100; int i = 0;
// find the next equal or smallest rate
while (rates[i] && in_rate < rates[i])
i++;
out_sample_rate = rates[i] ? rates[i] : 44100;
out_channels = c->channels; out_channels = c->channels;
if (c->channel_layout == 0) { if (c->channel_layout == 0) {
// FIXME -- need to guess, looks pretty much like a bug in the FFMPEG WMA decoder // FIXME -- need to guess, looks pretty much like a bug in the FFMPEG WMA decoder
@@ -304,9 +313,16 @@ bool WriterPCM::Write(AVPacket *packet, int64_t pts)
unsigned int packet_size = packet->size; unsigned int packet_size = packet->size;
while (packet_size > 0 || (!packet_size && !packet->data)) { while (packet_size > 0 || (!packet_size && !packet->data)) {
av_frame_unref(decoded_frame);
int got_frame = 0; int got_frame = 0;
if (!decoded_frame) {
if (!(decoded_frame = av_frame_alloc())) {
fprintf(stderr, "out of memory\n");
exit(1);
}
} else
av_frame_unref(decoded_frame);
int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, packet); int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, packet);
if (len < 0) { if (len < 0) {
restart_audio_resampling = true; restart_audio_resampling = true;

View File

@@ -53,8 +53,8 @@ int InsertPesHeader(uint8_t *data, int size, uint8_t stream_id, int64_t pts, int
{ {
BitPacker_t ld2 = { data, 0, 32 }; BitPacker_t ld2 = { data, 0, 32 };
if (size > MAX_PES_PACKET_SIZE) /* if (size > MAX_PES_PACKET_SIZE)
size = 0; // unbounded size = 0; // unbounded */
PutBits(&ld2, 0x0, 8); PutBits(&ld2, 0x0, 8);
PutBits(&ld2, 0x0, 8); PutBits(&ld2, 0x0, 8);

View File

@@ -66,20 +66,23 @@ bool Writer::Write(AVPacket * /* packet */, int64_t /* pts */)
static Writer writer __attribute__ ((init_priority (300))); static Writer writer __attribute__ ((init_priority (300)));
Writer *Writer::GetWriter(enum AVCodecID id, enum AVMediaType codec_type) Writer *Writer::GetWriter(enum AVCodecID id, enum AVMediaType codec_type, int track_type)
{ {
std::map<enum AVCodecID,Writer*>::iterator it = writers.find(id); fprintf(stderr, "GETWRITER %d %d %d", id, codec_type, track_type);
if (track_type != 6) { // hack for ACC resampling
std::map<enum AVCodecID,Writer*>::iterator it = writers.find(id);
if (it != writers.end()) if (it != writers.end())
return it->second; return it->second;
}
switch (codec_type) { switch (codec_type) {
case AVMEDIA_TYPE_AUDIO: case AVMEDIA_TYPE_AUDIO:
if (id == AV_CODEC_ID_INJECTPCM) // should not happen if (id == AV_CODEC_ID_INJECTPCM) // should not happen
break; break;
return GetWriter(AV_CODEC_ID_INJECTPCM, codec_type); return GetWriter(AV_CODEC_ID_INJECTPCM, codec_type, 100);
case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_VIDEO:
if (id == AV_CODEC_ID_MPEG2TS) // should not happen if (id == AV_CODEC_ID_MPEG2TS) // should not happen
break; break;
return GetWriter(AV_CODEC_ID_MPEG2TS, codec_type); return GetWriter(AV_CODEC_ID_MPEG2TS, codec_type, 100);
default: default:
break; break;
} }