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 deleted file mode 100644 index 44f03d4..0000000 --- a/libeplayer3/writer/flac.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * linuxdvb output/writer handling - * - * Copyright (C) 2010 konfetti (based on code from libeplayer2) - * Copyright (C) 2014 martii (based on code from libeplayer3) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "pes.h" -#include "misc.h" -#include "writer.h" - -class WriterFLAC : public Writer -{ - public: - bool Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t pts); - WriterFLAC(); -}; - -bool WriterFLAC::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t pts) -{ - if (fd < 0 || !packet) - 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; - - return writev(fd, iov, 2) > -1; -} - -WriterFLAC::WriterFLAC() -{ - Register(this, AV_CODEC_ID_FLAC, AUDIO_ENCODING_LPCM); -} - -static WriterFLAC writer_flac __attribute__ ((init_priority (300))); 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) { diff --git a/libeplayer3/writer/writer.cpp b/libeplayer3/writer/writer.cpp index e15a426..82f199c 100644 --- a/libeplayer3/writer/writer.cpp +++ b/libeplayer3/writer/writer.cpp @@ -34,7 +34,6 @@ #include "ac3.cpp" #include "divx.cpp" #include "dts.cpp" -#include "flac.cpp" #include "h263.cpp" #include "h264.cpp" #include "mp3.cpp" diff --git a/libspark/init.cpp b/libspark/init.cpp index f316eac..d358995 100644 --- a/libspark/init.cpp +++ b/libspark/init.cpp @@ -57,7 +57,7 @@ static input_device_t input_device[] = { { NULL, NULL, -1, 0, 0, 0 } }; -static int number_of_input_devices = 0; +#define number_of_input_devices (sizeof(input_device)/sizeof(input_device_t) - 1) static void do_mknod(int i, char *d_name) { char name[255]; @@ -102,7 +102,7 @@ static void create_input_devices (void) { buf[l--] = 0; while (l > 1 && buf[l] == '\n'); - for (int i = 0; i < number_of_input_devices; i++) + for (unsigned int i = 0; i < number_of_input_devices; i++) if (input_device[i].desc && !strcmp(buf, input_device[i].desc)) { do_mknod(i, e->d_name); break; @@ -124,7 +124,7 @@ static void create_input_devices (void) { struct stat st; if (stat(name, &st)) continue; - for (int i = 0; i < number_of_input_devices; i++) + for (unsigned int i = 0; i < number_of_input_devices; i++) if (input_device[i].major && gnu_dev_major(st.st_rdev) == input_device[i].major && gnu_dev_minor(st.st_rdev) == input_device[i].minor) @@ -137,15 +137,9 @@ static void create_input_devices (void) { static pthread_t inmux_task = 0; static int inmux_thread_running = 0; -static void count_input_devices(void) { - input_device_t *i = input_device; - while (i->name) - i++, number_of_input_devices++; -} - static void open_input_devices(void) { time_t now = time(NULL); - for (int i = 0; i < number_of_input_devices; i++) + for (unsigned int i = 0; i < number_of_input_devices; i++) if ((input_device[i].fd < 0) && (input_device[i].next_discovery <= now)) { input_device[i].next_discovery = now + 60; input_device[i].fd = open(input_device[i].name, O_RDWR | O_NONBLOCK); @@ -155,7 +149,7 @@ static void open_input_devices(void) { static void reopen_input_devices(void) { create_input_devices(); time_t now = time(NULL); - for (int i = 0; i < number_of_input_devices; i++) { + for (unsigned int i = 0; i < number_of_input_devices; i++) { input_device[i].next_discovery = now + 60; int fd = open(input_device[i].name, O_RDWR | O_NONBLOCK); if (fd > -1) { @@ -173,7 +167,7 @@ static void reopen_input_devices(void) { } static void close_input_devices(void) { - for (int i = 0; i < number_of_input_devices; i++) + for (unsigned int i = 0; i < number_of_input_devices; i++) if (input_device[i].fd > -1) { close(input_device[i].fd); input_device[i].fd = -1; @@ -184,7 +178,7 @@ static void poll_input_devices(void) { struct pollfd fds[number_of_input_devices]; input_device_t *inputs[number_of_input_devices]; int nfds = 0; - for (int i = 1; i < number_of_input_devices; i++) + for (unsigned int i = 1; i < number_of_input_devices; i++) if (input_device[i].fd > -1) { fds[nfds].fd = input_device[i].fd; fds[nfds].events = POLLIN | POLLHUP | POLLERR; @@ -274,7 +268,6 @@ void init_td_api() { cCpuFreqManager f; f.SetCpuFreq(0); /* CPUFREQ == 0 is the trigger for leaving standby */ - count_input_devices(); create_input_devices(); start_inmux_thread();