diff --git a/libeplayer3/Makefile.am b/libeplayer3/Makefile.am index 7a6b9e0..0ba2609 100644 --- a/libeplayer3/Makefile.am +++ b/libeplayer3/Makefile.am @@ -9,7 +9,7 @@ libeplayer3_la_SOURCES = \ input.cpp output.cpp manager.cpp player.cpp \ writer/writer.cpp writer/wmv.cpp writer/ac3.cpp writer/divx.cpp writer/pes.cpp \ writer/dts.cpp writer/mpeg2.cpp writer/mp3.cpp writer/misc.cpp writer/h264.cpp \ - writer/h263.cpp writer/vc1.cpp writer/flac.cpp writer/pcm.cpp + writer/h263.cpp writer/vc1.cpp writer/pcm.cpp LIBEPLAYER3_LIBS = libeplayer3.la -lpthread -lavformat -lavcodec -lavutil -lswresample -lm diff --git a/libeplayer3/input.cpp b/libeplayer3/input.cpp index 1301052..501cf88 100644 --- a/libeplayer3/input.cpp +++ b/libeplayer3/input.cpp @@ -230,7 +230,8 @@ bool Input::Play() } } } else if (_teletextTrack && (_teletextTrack->stream == stream)) { - teletext_write(stream->id, packet.data, packet.size); + if (packet.data && packet.size > 1) + teletext_write(stream->id, packet.data + 1, packet.size - 1); } av_free_packet(&packet); @@ -238,8 +239,17 @@ bool Input::Play() if (player->abortRequested) player->output.Clear(); - else + else { + Track *_audioTrack = audioTrack; + if (_audioTrack) { + // flush audio decoder + AVPacket packet; + av_init_packet(&packet); + packet.size = 0; + player->output.Write(avfc, _audioTrack->stream, &packet, 0); + } player->output.Flush(); + } dvbsub_ass_clear(); abortPlayback = true; diff --git a/libeplayer3/writer/ac3.cpp b/libeplayer3/writer/ac3.cpp index 7ac84e3..dac0664 100644 --- a/libeplayer3/writer/ac3.cpp +++ b/libeplayer3/writer/ac3.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "misc.h" #include "pes.h" #include "writer.h" @@ -39,18 +41,26 @@ class WriterAC3 : public Writer bool WriterAC3::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_MAX_HEADER_SIZE]; - struct iovec iov[2]; - iov[0].iov_base = PesHeader; - iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, PRIVATE_STREAM_1_PES_START_CODE, pts, 0); - iov[1].iov_base = packet->data; - iov[1].iov_len = packet->size; + for (int pos = 0; pos < packet->size; ) { + int PacketLength = std::min(packet->size - pos, MAX_PES_PACKET_SIZE); + struct iovec iov[2]; + iov[0].iov_base = PesHeader; + iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, PRIVATE_STREAM_1_PES_START_CODE, pts, 0); + iov[1].iov_base = packet->data + pos; + iov[1].iov_len = PacketLength; - return writev(fd, iov, 2) > -1; + ssize_t l = writev(fd, iov, 2); + if (l < 0) + return false; + pos += PacketLength; + pts = INVALID_PTS_VALUE; + } + return true; } WriterAC3::WriterAC3() diff --git a/libeplayer3/writer/divx.cpp b/libeplayer3/writer/divx.cpp index 283ef63..12af898 100644 --- a/libeplayer3/writer/divx.cpp +++ b/libeplayer3/writer/divx.cpp @@ -50,7 +50,7 @@ void WriterDIVX::Init() bool WriterDIVX::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_MAX_HEADER_SIZE]; diff --git a/libeplayer3/writer/dts.cpp b/libeplayer3/writer/dts.cpp index 2ac0ec8..356bb95 100644 --- a/libeplayer3/writer/dts.cpp +++ b/libeplayer3/writer/dts.cpp @@ -42,7 +42,7 @@ class WriterDTS : public Writer bool WriterDTS::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_AUDIO_HEADER_SIZE]; diff --git a/libeplayer3/writer/flac.cpp b/libeplayer3/writer/flac.cpp index 44f03d4..a7a56d6 100644 --- a/libeplayer3/writer/flac.cpp +++ b/libeplayer3/writer/flac.cpp @@ -26,8 +26,10 @@ #include #include -#include "pes.h" +#include + #include "misc.h" +#include "pes.h" #include "writer.h" class WriterFLAC : public Writer @@ -39,18 +41,26 @@ class WriterFLAC : public Writer bool WriterFLAC::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_MAX_HEADER_SIZE]; - struct iovec iov[2]; - iov[0].iov_base = PesHeader; - iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0); - iov[1].iov_base = packet->data; - iov[1].iov_len = packet->size; + for (int pos = 0; pos < packet->size; ) { + int PacketLength = std::min(packet->size - pos, MAX_PES_PACKET_SIZE); + struct iovec iov[2]; + iov[0].iov_base = PesHeader; + iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_AUDIO_PES_START_CODE, pts, 0); + iov[1].iov_base = packet->data + pos; + iov[1].iov_len = PacketLength; - return writev(fd, iov, 2) > -1; + ssize_t l = writev(fd, iov, 2); + if (l < 0) + return false; + pos += PacketLength; + pts = INVALID_PTS_VALUE; + } + return true; } WriterFLAC::WriterFLAC() diff --git a/libeplayer3/writer/h263.cpp b/libeplayer3/writer/h263.cpp index aa0c30e..1924506 100644 --- a/libeplayer3/writer/h263.cpp +++ b/libeplayer3/writer/h263.cpp @@ -38,7 +38,7 @@ class WriterH263 : public Writer bool WriterH263::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_MAX_HEADER_SIZE]; diff --git a/libeplayer3/writer/h264.cpp b/libeplayer3/writer/h264.cpp index 1d65c1c..ecaefc3 100644 --- a/libeplayer3/writer/h264.cpp +++ b/libeplayer3/writer/h264.cpp @@ -66,7 +66,7 @@ void WriterH264::Init(void) bool WriterH264::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_MAX_HEADER_SIZE]; unsigned int TimeDelta; diff --git a/libeplayer3/writer/mp3.cpp b/libeplayer3/writer/mp3.cpp index 024bb4f..cb9f99b 100644 --- a/libeplayer3/writer/mp3.cpp +++ b/libeplayer3/writer/mp3.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "misc.h" #include "pes.h" #include "writer.h" @@ -39,18 +41,26 @@ class WriterMP3 : public Writer bool WriterMP3::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_MAX_HEADER_SIZE]; - struct iovec iov[2]; - iov[0].iov_base = PesHeader; - iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0); - iov[1].iov_base = packet->data; - iov[1].iov_len = packet->size; + for (int pos = 0; pos < packet->size; ) { + int PacketLength = std::min(packet->size - pos, MAX_PES_PACKET_SIZE); + struct iovec iov[2]; + iov[0].iov_base = PesHeader; + iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_AUDIO_PES_START_CODE, pts, 0); + iov[1].iov_base = packet->data + pos; + iov[1].iov_len = PacketLength; - return writev(fd, iov, 2) > -1; + ssize_t l = writev(fd, iov, 2); + if (l < 0) + return false; + pos += PacketLength; + pts = INVALID_PTS_VALUE; + } + return true; } WriterMP3::WriterMP3() @@ -58,6 +68,7 @@ WriterMP3::WriterMP3() Register(this, AV_CODEC_ID_MP3, AUDIO_ENCODING_MP3); Register(this, AV_CODEC_ID_MP2, AUDIO_ENCODING_MPEG2); // Register(this, AV_CODEC_ID_VORBIS, AUDIO_ENCODING_VORBIS); + Register(this, AV_CODEC_ID_FLAC, AUDIO_ENCODING_LPCM); } static WriterMP3 writer_mp3 __attribute__ ((init_priority (300))); diff --git a/libeplayer3/writer/mpeg2.cpp b/libeplayer3/writer/mpeg2.cpp index a9143ec..4577807 100644 --- a/libeplayer3/writer/mpeg2.cpp +++ b/libeplayer3/writer/mpeg2.cpp @@ -41,25 +41,23 @@ class WriterMPEG2 : public Writer bool WriterMPEG2::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; uint8_t PesHeader[PES_MAX_HEADER_SIZE]; - for (int Position = 0; Position < packet->size; ) { - int PacketLength = std::min(packet->size - Position, MAX_PES_PACKET_SIZE); + for (int pos = 0; pos < packet->size; ) { + int PacketLength = std::min(packet->size - pos, MAX_PES_PACKET_SIZE); struct iovec iov[2]; iov[0].iov_base = PesHeader; - iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, 0xe0, pts, 0); - iov[1].iov_base = packet->data + Position; + iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, pts, 0); + iov[1].iov_base = packet->data + pos; iov[1].iov_len = PacketLength; ssize_t l = writev(fd, iov, 2); - if (l < 0) { + if (l < 0) return false; - break; - } - Position += PacketLength; + pos += PacketLength; pts = INVALID_PTS_VALUE; } return true; diff --git a/libeplayer3/writer/pcm.cpp b/libeplayer3/writer/pcm.cpp index cfc42dd..bbc56d3 100644 --- a/libeplayer3/writer/pcm.cpp +++ b/libeplayer3/writer/pcm.cpp @@ -64,6 +64,8 @@ class WriterPCM : public Writer uint8_t lpcm_prv[14]; uint8_t injectBuffer[2048]; uint8_t breakBuffer[sizeof(injectBuffer)]; + uint8_t *output; + uint8_t out_samples_max; unsigned int breakBufferFillSize; int uNoOfChannels; int uSampleRate; @@ -209,7 +211,7 @@ bool WriterPCM::writePCM(int fd, int64_t Pts, uint8_t *data, unsigned int size) break; } } - if (size) { + if (size && res) { breakBufferFillSize = size; memcpy(breakBuffer, data, size); } @@ -234,20 +236,19 @@ bool WriterPCM::Write(int fd, AVFormatContext * /*avfc*/, AVStream *stream, AVPa } AVCodecContext *c = stream->codec; - unsigned int packet_size = packet->size; if (restart_audio_resampling) { restart_audio_resampling = false; initialHeader = true; - if (swr) - swr_free(&swr); - if (decoded_frame) - av_frame_free(&decoded_frame); + swr_free(&swr); AVCodec *codec = avcodec_find_decoder(c->codec_id); - - if (!codec || avcodec_open2(c, codec, NULL)) { + if (!codec) { + fprintf(stderr, "%s %d: avcodec_find_decoder(%llx)\n", __func__, __LINE__, (unsigned long long) c->codec_id); + return false; + } + if (avcodec_open2(c, codec, NULL)) { fprintf(stderr, "%s %d: avcodec_open2 failed\n", __func__, __LINE__); return false; } @@ -294,59 +295,62 @@ bool WriterPCM::Write(int fd, AVFormatContext * /*avfc*/, AVStream *stream, AVPa fprintf(stderr, "swr_init: %d (icl=%d ocl=%d isr=%d osr=%d isf=%d osf=%d\n", -e, (int) c->channel_layout, (int) out_channel_layout, c->sample_rate, out_sample_rate, c->sample_fmt, AV_SAMPLE_FMT_S16); - swr_free(&swr); restart_audio_resampling = true; return false; } } - while (packet_size > 0) { - int got_frame = 0; - if (decoded_frame) - av_frame_unref(decoded_frame); - else if (!(decoded_frame = av_frame_alloc())) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + unsigned int packet_size = packet->size; + while (packet_size > 0 || (!packet_size && !packet->data)) { + av_frame_unref(decoded_frame); + int got_frame = 0; int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, packet); if (len < 0) { restart_audio_resampling = true; break; } - packet_size -= len; - - if (!got_frame) + if (!got_frame) { + if (!packet->data) + break; continue; + } int in_samples = decoded_frame->nb_samples; int out_samples = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + in_samples, out_sample_rate, c->sample_rate, AV_ROUND_UP); - - uint8_t *output = NULL; - int e = av_samples_alloc(&output, NULL, out_channels, out_samples, AV_SAMPLE_FMT_S16, 1); - if (e < 0) { - fprintf(stderr, "av_samples_alloc: %d\n", -e); - break; + if (out_samples > out_samples_max) { + if (output) + av_freep(&output); + int e = av_samples_alloc(&output, NULL, out_channels, out_samples, AV_SAMPLE_FMT_S16, 1); + if (e < 0) { + fprintf(stderr, "av_samples_alloc: %d\n", -e); + break; + } + out_samples_max = out_samples; } + out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **) &decoded_frame->data[0], in_samples); - if(!writePCM(fd, pts, output, out_samples * sizeof(short) * out_channels)) { + if (!writePCM(fd, pts, output, out_samples * sizeof(short) * out_channels)) { restart_audio_resampling = true; - av_free(output); break; } - av_free(output); pts = 0; + + if (packet->data) + packet_size -= len; } - return true; + return !packet_size; } WriterPCM::WriterPCM() { swr = NULL; - decoded_frame = NULL; + output = NULL; + out_samples_max = 0; + decoded_frame = av_frame_alloc(); Register(this, AV_CODEC_ID_INJECTPCM, AUDIO_ENCODING_LPCMA); Init(); diff --git a/libeplayer3/writer/vc1.cpp b/libeplayer3/writer/vc1.cpp index 74152aa..d3ce02a 100644 --- a/libeplayer3/writer/vc1.cpp +++ b/libeplayer3/writer/vc1.cpp @@ -63,7 +63,7 @@ void WriterVC1::Init() bool WriterVC1::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; if (initialHeader) { diff --git a/libeplayer3/writer/wmv.cpp b/libeplayer3/writer/wmv.cpp index 644c8ce..10220d1 100644 --- a/libeplayer3/writer/wmv.cpp +++ b/libeplayer3/writer/wmv.cpp @@ -70,7 +70,7 @@ void WriterWMV::Init() bool WriterWMV::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t pts) { - if (fd < 0 || !packet) + if (fd < 0 || !packet || !packet->data) return false; if (initialHeader) {