From 704bcc5a210d4fe51d9a4f5d789b730701d81a87 Mon Sep 17 00:00:00 2001 From: max_10 Date: Tue, 10 Apr 2018 11:31:57 +0200 Subject: [PATCH] libeplayer3-arm: insert original blank lines from exteplayer3.git, for better merge --- libeplayer3-arm/Makefile.am | 2 +- libeplayer3-arm/container/buff_ffmpeg.c | 75 ++++- libeplayer3-arm/container/container.c | 12 + libeplayer3-arm/container/container_ffmpeg.c | 311 +++++++++++++++++- libeplayer3-arm/container/flv2mpeg4_ffmpeg.c | 13 + libeplayer3-arm/container/mpeg4p2_ffmpeg.c | 5 + libeplayer3-arm/container/wrapped_ffmpeg.c | 5 + libeplayer3-arm/external/ffmpeg/get_bits.h | 13 + libeplayer3-arm/external/ffmpeg/latmenc.h | 1 + libeplayer3-arm/external/ffmpeg/put_bits.h | 7 + .../external/ffmpeg/src/bitstream.c | 6 + libeplayer3-arm/external/ffmpeg/src/latmenc.c | 25 ++ .../external/ffmpeg/src/mpeg4audio.c | 16 + .../external/flv2mpeg4/src/bitreader.h | 9 + .../external/flv2mpeg4/src/bitwriter.h | 7 + .../external/flv2mpeg4/src/dcprediction.c | 12 + .../external/flv2mpeg4/src/dcprediction.h | 1 + libeplayer3-arm/external/flv2mpeg4/src/flv.h | 2 + .../external/flv2mpeg4/src/flv2mpeg4.c | 40 +++ .../external/flv2mpeg4/src/flvdecoder.c | 48 +++ libeplayer3-arm/external/flv2mpeg4/src/m4v.h | 2 + .../external/flv2mpeg4/src/m4vencode.c | 76 +++++ libeplayer3-arm/include/aac.h | 1 + libeplayer3-arm/include/bcm_ioctls.h | 7 + libeplayer3-arm/include/debug.h | 2 + libeplayer3-arm/include/manager.h | 2 + libeplayer3-arm/include/misc.h | 6 + libeplayer3-arm/include/output.h | 1 + libeplayer3-arm/include/pes.h | 2 + libeplayer3-arm/include/stm_ioctls.h | 4 + libeplayer3-arm/include/writer.h | 4 +- libeplayer3-arm/main/exteplayer.c | 84 ++++- libeplayer3-arm/manager/audio.c | 37 ++- libeplayer3-arm/manager/chapter.c | 3 +- libeplayer3-arm/manager/manager.c | 5 + libeplayer3-arm/manager/subtitle.c | 4 +- libeplayer3-arm/manager/video.c | 23 +- libeplayer3-arm/output/linuxdvb_buffering.c | 122 ++++--- libeplayer3-arm/output/linuxdvb_mipsel.c | 165 +++++++++- libeplayer3-arm/output/linuxdvb_sh4.c | 182 +++++++++- libeplayer3-arm/output/output.c | 11 +- libeplayer3-arm/output/output_subtitle.c | 31 +- libeplayer3-arm/output/writer/common/misc.c | 5 + libeplayer3-arm/output/writer/common/pes.c | 15 + libeplayer3-arm/output/writer/mipsel/aac.c | 31 +- libeplayer3-arm/output/writer/mipsel/ac3.c | 11 + libeplayer3-arm/output/writer/mipsel/amr.c | 11 + libeplayer3-arm/output/writer/mipsel/divx3.c | 16 +- libeplayer3-arm/output/writer/mipsel/dts.c | 10 + libeplayer3-arm/output/writer/mipsel/h263.c | 9 + libeplayer3-arm/output/writer/mipsel/h264.c | 51 +++ libeplayer3-arm/output/writer/mipsel/h265.c | 32 ++ libeplayer3-arm/output/writer/mipsel/lpcm.c | 21 +- libeplayer3-arm/output/writer/mipsel/mp3.c | 9 + libeplayer3-arm/output/writer/mipsel/mpeg2.c | 13 + libeplayer3-arm/output/writer/mipsel/mpeg4.c | 11 + libeplayer3-arm/output/writer/mipsel/pcm.c | 28 +- libeplayer3-arm/output/writer/mipsel/vc1.c | 15 + libeplayer3-arm/output/writer/mipsel/vp.c | 9 +- libeplayer3-arm/output/writer/mipsel/wma.c | 15 +- libeplayer3-arm/output/writer/mipsel/wmv.c | 15 + libeplayer3-arm/output/writer/mipsel/writer.c | 32 +- libeplayer3-arm/output/writer/sh4/aac.c | 32 ++ libeplayer3-arm/output/writer/sh4/ac3.c | 9 + libeplayer3-arm/output/writer/sh4/divx.c | 15 + libeplayer3-arm/output/writer/sh4/divx2.c | 19 ++ libeplayer3-arm/output/writer/sh4/dts.c | 11 + libeplayer3-arm/output/writer/sh4/h263.c | 13 + libeplayer3-arm/output/writer/sh4/h264.c | 69 ++++ libeplayer3-arm/output/writer/sh4/mp3.c | 9 + libeplayer3-arm/output/writer/sh4/mpeg2.c | 14 + libeplayer3-arm/output/writer/sh4/pcm.c | 26 ++ libeplayer3-arm/output/writer/sh4/pes.c | 14 + libeplayer3-arm/output/writer/sh4/vc1.c | 30 ++ libeplayer3-arm/output/writer/sh4/vorbis.c | 14 +- libeplayer3-arm/output/writer/sh4/wma.c | 15 +- libeplayer3-arm/output/writer/sh4/wmv.c | 31 ++ libeplayer3-arm/output/writer/sh4/writer.c | 9 + libeplayer3-arm/playback/playback.c | 114 ++++++- 79 files changed, 2070 insertions(+), 117 deletions(-) diff --git a/libeplayer3-arm/Makefile.am b/libeplayer3-arm/Makefile.am index 1f7f51e..b77dbf9 100644 --- a/libeplayer3-arm/Makefile.am +++ b/libeplayer3-arm/Makefile.am @@ -19,9 +19,9 @@ libeplayer3_arm_la_SOURCES = \ manager/subtitle.c \ manager/chapter.c \ output/linuxdvb_mipsel.c \ + output/linuxdvb_buffering.c \ output/output_subtitle.c \ output/output.c \ - output/linuxdvb_buffering.c \ output/writer/common/pes.c \ output/writer/common/misc.c \ output/writer/mipsel/writer.c \ diff --git a/libeplayer3-arm/container/buff_ffmpeg.c b/libeplayer3-arm/container/buff_ffmpeg.c index 61ac32d..3386b7f 100644 --- a/libeplayer3-arm/container/buff_ffmpeg.c +++ b/libeplayer3-arm/container/buff_ffmpeg.c @@ -95,15 +95,19 @@ static void update_finish_timeout() int64_t currPts = -1; int32_t ret = g_context->playback->Command(g_context, PLAYBACK_PTS, &currPts); finishTimeout += 1; + if (maxInjectedPts < 0 || maxInjectedPts == INVALID_PTS_VALUE) { maxInjectedPts = 0; } + //printf("ret[%d] playPts[%lld] currPts[%lld] maxInjectedPts[%lld]\n", ret, playPts, currPts, maxInjectedPts); + /* On some STBs PTS readed from decoder is invalid after seek or at start * this is the reason for additional validation when we what to close immediately */ - if (!progressive_playback && 0 == ret && currPts >= maxInjectedPts && ((currPts - maxInjectedPts) / 90000) < 2) + if (!progressive_playback && 0 == ret && currPts >= maxInjectedPts && + ((currPts - maxInjectedPts) / 90000) < 2) { /* close immediately */ @@ -129,6 +133,7 @@ static int32_t ffmpeg_read_wrapper_base(void *opaque, uint8_t *buf, int32_t buf_ { break; } + int32_t partLen = ffmpeg_real_read_org(opaque, buf + len, buf_size - len); if (partLen > 0) { @@ -141,7 +146,9 @@ static int32_t ffmpeg_read_wrapper_base(void *opaque, uint8_t *buf, int32_t buf_ len = 0; break; } + update_finish_timeout(); + usleep(100000); continue; } @@ -163,25 +170,31 @@ static int32_t ffmpeg_read_wrapper(void *opaque, uint8_t *buf, int32_t buf_size) return ffmpeg_real_read_org(opaque, buf, buf_size); } } + #if 0 static int32_t ffmpeg_read_wrapper2(void *opaque, uint8_t *buf, int32_t buf_size) { return ffmpeg_read_wrapper_base(opaque, buf, buf_size, 1); } #endif + //for buffered io void getfillerMutex(const char *filename __attribute__((unused)), const char *function __attribute__((unused)), int line __attribute__((unused))) { ffmpeg_printf(100, "::%d requesting mutex\n", line); + pthread_mutex_lock(&fillermutex); + ffmpeg_printf(100, "::%d received mutex\n", line); } void releasefillerMutex(const char *filename __attribute__((unused)), const const char *function __attribute__((unused)), int line __attribute__((unused))) { pthread_mutex_unlock(&fillermutex); + ffmpeg_printf(100, "::%d released mutex\n", line); } + //for buffered io (end)encoding #if 0 static int32_t container_set_ffmpeg_buf_seek_time(int32_t *time) @@ -190,6 +203,7 @@ static int32_t container_set_ffmpeg_buf_seek_time(int32_t *time) return cERR_CONTAINER_FFMPEG_NO_ERROR; } #endif + static int32_t container_set_ffmpeg_buf_size(int32_t *size) { if (ffmpeg_buf == NULL) @@ -203,6 +217,7 @@ static int32_t container_set_ffmpeg_buf_size(int32_t *size) ffmpeg_buf_size = (*size) + FILLBUFDIFF; } } + ffmpeg_printf(10, "size=%d, buffer size=%d\n", (*size), ffmpeg_buf_size); return cERR_CONTAINER_FFMPEG_NO_ERROR; } @@ -216,6 +231,7 @@ static int32_t container_get_ffmpeg_buf_size(int32_t *size) static int32_t container_get_fillbufstatus(int32_t *size) { int32_t rwdiff = 0; + if (ffmpeg_buf != NULL && ffmpeg_buf_read != NULL && ffmpeg_buf_write != NULL) { if (ffmpeg_buf_read < ffmpeg_buf_write) @@ -225,10 +241,13 @@ static int32_t container_get_fillbufstatus(int32_t *size) rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read; rwdiff += ffmpeg_buf_write - ffmpeg_buf; } + *size = rwdiff; } + return cERR_CONTAINER_FFMPEG_NO_ERROR; } + #if 0 static int32_t container_stop_buffer() { @@ -236,6 +255,7 @@ static int32_t container_stop_buffer() return 0; } #endif + //flag 0: start direct //flag 1: from thread static void ffmpeg_filler(Context_t *context, int32_t id, int32_t *inpause, int32_t flag) @@ -243,11 +263,13 @@ static void ffmpeg_filler(Context_t *context, int32_t id, int32_t *inpause, int3 int32_t len = 0; int32_t rwdiff = ffmpeg_buf_size; uint8_t buf[FILLBUFPAKET]; + if (ffmpeg_read_org == NULL || ffmpeg_seek_org == NULL) { ffmpeg_err("ffmpeg_read_org or ffmpeg_seek_org is NULL\n"); return; } + while ((flag == 0 && avContextTab[0] != NULL && avContextTab[0]->pb != NULL && rwdiff > FILLBUFDIFF) || (flag == 1 && hasfillerThreadStarted[id] == 1 && avContextTab[0] != NULL && avContextTab[0]->pb != NULL && rwdiff > FILLBUFDIFF)) { @@ -255,11 +277,13 @@ static void ffmpeg_filler(Context_t *context, int32_t id, int32_t *inpause, int3 { break; } + if (flag == 0 && ffmpeg_buf_stop == 1) { ffmpeg_buf_stop = 0; break; } + getfillerMutex(__FILE__, __FUNCTION__, __LINE__); //do a seek if (ffmpeg_do_seek != 0) @@ -270,42 +294,53 @@ static void ffmpeg_filler(Context_t *context, int32_t id, int32_t *inpause, int3 ffmpeg_buf_write = ffmpeg_buf; ffmpeg_buf_read = ffmpeg_buf; } + ffmpeg_do_seek = 0; } + if (ffmpeg_buf_read == ffmpeg_buf_write) { ffmpeg_buf_valid_size = 0; rwdiff = ffmpeg_buf_size; } + if (ffmpeg_buf_read < ffmpeg_buf_write) { rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_write; rwdiff += ffmpeg_buf_read - ffmpeg_buf; } + if (ffmpeg_buf_read > ffmpeg_buf_write) { rwdiff = ffmpeg_buf_read - ffmpeg_buf_write; } + int32_t size = FILLBUFPAKET; if (rwdiff - FILLBUFDIFF < size) { size = (rwdiff - FILLBUFDIFF); } + if (ffmpeg_buf_write + size > ffmpeg_buf + ffmpeg_buf_size) { size = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_write; } + if (ffmpeg_buf_write == ffmpeg_buf + ffmpeg_buf_size) { ffmpeg_buf_write = ffmpeg_buf; } + releasefillerMutex(__FILE__, __FUNCTION__, __LINE__); + if (size > 0) { if (flag == 1 && hasfillerThreadStarted[id] == 2) break; len = ffmpeg_read_org(avContextTab[0]->pb->opaque, buf, size); if (flag == 1 && hasfillerThreadStarted[id] == 2) break; + ffmpeg_printf(20, "buffer-status (free buffer=%d)\n", rwdiff - FILLBUFDIFF - len); + getfillerMutex(__FILE__, __FUNCTION__, __LINE__); if (len > 0) { @@ -333,11 +368,13 @@ static void ffmpeg_filler(Context_t *context, int32_t id, int32_t *inpause, int3 { int32_t buflen = 0; (*inpause) = 0; + getfillerMutex(__FILE__, __FUNCTION__, __LINE__); if (ffmpeg_buf_read < ffmpeg_buf_write) { buflen = ffmpeg_buf_write - ffmpeg_buf_read; } + if (ffmpeg_buf_read > ffmpeg_buf_write) { buflen = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read; @@ -355,13 +392,17 @@ static void ffmpeg_fillerTHREAD(Context_t *context) { int32_t inpause = 0; int32_t id = hasfillerThreadStartedID; + ffmpeg_printf(10, "Running ID=%d!\n", id); + while (hasfillerThreadStarted[id] == 1) { ffmpeg_filler(context, id, &inpause, 1); usleep(10000); } + hasfillerThreadStarted[id] = 0; + ffmpeg_printf(10, "terminating ID=%d\n", id); } @@ -370,7 +411,9 @@ static int32_t ffmpeg_start_fillerTHREAD(Context_t *context) int32_t error; int32_t ret = 0, i = 0; pthread_attr_t attr; + ffmpeg_printf(10, "\n"); + if (context && context->playback && context->playback->isPlaying) { ffmpeg_printf(10, "is Playing\n"); @@ -379,6 +422,7 @@ static int32_t ffmpeg_start_fillerTHREAD(Context_t *context) { ffmpeg_printf(10, "is NOT Playing\n"); } + //get filler thread ID //if the thread hangs for long time, we use a new id for (i = 0; i < 10; i++) @@ -389,15 +433,18 @@ static int32_t ffmpeg_start_fillerTHREAD(Context_t *context) break; } } + if (hasfillerThreadStarted[hasfillerThreadStartedID] == 0) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + hasfillerThreadStarted[hasfillerThreadStartedID] = 1; if ((error = pthread_create(&fillerThread, &attr, (void *)&ffmpeg_fillerTHREAD, context)) != 0) { hasfillerThreadStarted[hasfillerThreadStartedID] = 0; ffmpeg_printf(10, "Error creating filler thread, error:%d:%s\n", error, strerror(error)); + ret = cERR_CONTAINER_FFMPEG_ERR; } else @@ -408,8 +455,10 @@ static int32_t ffmpeg_start_fillerTHREAD(Context_t *context) else { ffmpeg_printf(10, "All filler thread ID's in use!\n"); + ret = cERR_CONTAINER_FFMPEG_ERR; } + ffmpeg_printf(10, "exiting with value %d\n", ret); return ret; } @@ -418,9 +467,11 @@ static int32_t ffmpeg_read_real(void *opaque __attribute__((unused)), uint8_t *b { int32_t len = buf_size; int32_t rwdiff = 0; + if (buf_size > 0) { getfillerMutex(__FILE__, __FUNCTION__, __LINE__); + if (ffmpeg_buf_read < ffmpeg_buf_write) rwdiff = ffmpeg_buf_write - ffmpeg_buf_read; if (ffmpeg_buf_read > ffmpeg_buf_write) @@ -429,18 +480,22 @@ static int32_t ffmpeg_read_real(void *opaque __attribute__((unused)), uint8_t *b rwdiff += ffmpeg_buf_write - ffmpeg_buf; } rwdiff--; + if (len > rwdiff) { len = rwdiff; } + if (ffmpeg_buf_read + len > ffmpeg_buf + ffmpeg_buf_size) { len = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read; } + if (len > 0) { memcpy(buf, ffmpeg_buf_read, len); ffmpeg_buf_read += len; + if (ffmpeg_buf_valid_size < FILLBUFDIFF) { if (ffmpeg_buf_valid_size + len > FILLBUFDIFF) @@ -452,6 +507,7 @@ static int32_t ffmpeg_read_real(void *opaque __attribute__((unused)), uint8_t *b ffmpeg_buf_valid_size += len; } } + if (ffmpeg_buf_read == ffmpeg_buf + ffmpeg_buf_size) { ffmpeg_buf_read = ffmpeg_buf; @@ -463,6 +519,7 @@ static int32_t ffmpeg_read_real(void *opaque __attribute__((unused)), uint8_t *b } releasefillerMutex(__FILE__, __FUNCTION__, __LINE__); } + return len; } @@ -471,6 +528,7 @@ static int32_t ffmpeg_read(void *opaque, uint8_t *buf, int32_t buf_size) int32_t sumlen = 0; int32_t len = 0; int32_t count = 2000; + while (sumlen < buf_size && (--count) > 0 && 0 == PlaybackDieNow(0)) { len = ffmpeg_read_real(opaque, buf, buf_size - sumlen); @@ -481,6 +539,7 @@ static int32_t ffmpeg_read(void *opaque, uint8_t *buf, int32_t buf_size) usleep(10000); } } + if (count == 0) { if (sumlen == 0) @@ -492,6 +551,7 @@ static int32_t ffmpeg_read(void *opaque, uint8_t *buf, int32_t buf_size) ffmpeg_err("Timeout, not all buffered data availabel (buf_size=%d sumlen=%d)!\n", buf_size, sumlen); } } + return sumlen; } @@ -500,10 +560,12 @@ static int64_t ffmpeg_seek(void *opaque __attribute__((unused)), int64_t offset, int64_t diff; int32_t rwdiff = 0; whence &= ~AVSEEK_FORCE; + if (whence != SEEK_CUR && whence != SEEK_SET) { return AVERROR(EINVAL); } + if (whence == SEEK_CUR) { diff = offset; @@ -512,20 +574,25 @@ static int64_t ffmpeg_seek(void *opaque __attribute__((unused)), int64_t offset, { diff = offset - avContextTab[0]->pb->pos; } + if (diff == 0) { return avContextTab[0]->pb->pos; } + getfillerMutex(__FILE__, __FUNCTION__, __LINE__); + if (ffmpeg_buf_read < ffmpeg_buf_write) { rwdiff = ffmpeg_buf_write - ffmpeg_buf_read; } + if (ffmpeg_buf_read > ffmpeg_buf_write) { rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read; rwdiff += ffmpeg_buf_write - ffmpeg_buf; } + if (diff > 0 && diff < rwdiff) { /* can do the seek inside the buffer */ @@ -557,29 +624,35 @@ static int64_t ffmpeg_seek(void *opaque __attribute__((unused)), int64_t offset, { releasefillerMutex(__FILE__, __FUNCTION__, __LINE__); ffmpeg_printf(20, "real-seek diff=%lld\n", diff); + ffmpeg_do_seek_ret = 0; ffmpeg_do_seek = diff; while (ffmpeg_do_seek != 0) { usleep(100000); } + ffmpeg_do_seek = 0; if (ffmpeg_do_seek_ret < 0) { ffmpeg_err("seek not ok ret=%d\n", ffmpeg_do_seek_ret); return ffmpeg_do_seek_ret; } + //fill buffer int32_t count = ffmpeg_buf_seek_time * 10; int32_t size = 0; + container_get_fillbufstatus(&size); while (size < ffmpeg_buf_size - FILLBUFDIFF && (--count) > 0) { usleep(100000); container_get_fillbufstatus(&size); } + return avContextTab[0]->pb->pos + diff; } + releasefillerMutex(__FILE__, __FUNCTION__, __LINE__); return avContextTab[0]->pb->pos + diff; } diff --git a/libeplayer3-arm/container/container.c b/libeplayer3-arm/container/container.c index 3f56f21..48ea13a 100644 --- a/libeplayer3-arm/container/container.c +++ b/libeplayer3-arm/container/container.c @@ -56,8 +56,10 @@ static void printContainerCapabilities() { int32_t i = 0; int32_t j = 0; + container_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); container_printf(10, "Capabilities: "); + for (i = 0; AvailableContainer[i] != NULL; i++) { for (j = 0; AvailableContainer[i]->Capabilities[j] != NULL; j++) @@ -73,7 +75,9 @@ static int32_t selectContainer(Context_t *context, char *extension) int32_t i = 0; int32_t j = 0; int32_t ret = -1; + container_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + for (i = 0; AvailableContainer[i] != NULL; i++) { for (j = 0; AvailableContainer[i]->Capabilities[j] != NULL; j++) @@ -81,26 +85,32 @@ static int32_t selectContainer(Context_t *context, char *extension) if (!strcasecmp(AvailableContainer[i]->Capabilities[j], extension)) { context->container->selectedContainer = AvailableContainer[i]; + container_printf(10, "Selected Container: %s\n", context->container->selectedContainer->Name); ret = 0; break; } } + if (ret == 0) { break; } } + if (ret != 0) { container_err("No Container found :-(\n"); } + return ret; } + static int Command(Context_t *context, ContainerCmd_t command, void *argument __attribute__((unused))) { int ret = 0; + container_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); switch (command) @@ -124,9 +134,11 @@ static int Command(Context_t *context, ContainerCmd_t command, void *argument __ container_err("%s::%s ContainerCmd %d not supported!\n", __FILE__, __FUNCTION__, command); break; } + return ret; } + ContainerHandler_t ContainerHandler = { "Output", diff --git a/libeplayer3-arm/container/container_ffmpeg.c b/libeplayer3-arm/container/container_ffmpeg.c index 874e78f..f0f17c6 100644 --- a/libeplayer3-arm/container/container_ffmpeg.c +++ b/libeplayer3-arm/container/container_ffmpeg.c @@ -166,17 +166,21 @@ static void initMutex(void) static void getMutex(const char *filename __attribute__((unused)), const char *function __attribute__((unused)), int32_t line __attribute__((unused))) { ffmpeg_printf(100, "::%d requesting mutex\n", line); + if (!mutexInitialized) { initMutex(); } + pthread_mutex_lock(&mutex); + ffmpeg_printf(100, "::%d received mutex\n", line); } static void releaseMutex(const char *filename __attribute__((unused)), const const char *function __attribute__((unused)), int32_t line __attribute__((unused))) { pthread_mutex_unlock(&mutex); + ffmpeg_printf(100, "::%d released mutex\n", line); } @@ -194,6 +198,7 @@ static int32_t Write(Write_FN WriteFun, Context_t *context, void *privateData, i return ret; } + #include "buff_ffmpeg.c" #include "wrapped_ffmpeg.c" #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 34, 100) @@ -430,10 +435,12 @@ static char *Codec2Encoding(int32_t codec_id, int32_t media_type, uint8_t *extra return pcm_resampling ? "A_IPCM" : "A_PCM"; case AV_CODEC_ID_AMR_NB: return "A_IPCM";//return "A_AMR"; + /* In exteplayer3 embedded text subtitle simple printed * to output like other data. Maybe worth to consider is to use * linux socket or pipe to put */ + /* subtitle */ case AV_CODEC_ID_SSA: #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 3, 100) @@ -477,10 +484,12 @@ static int64_t calcPts(uint32_t avContextIdx, AVStream *stream, int64_t pts) { pts = av_rescale(pts, (int64_t)stream->time_base.num * 90000, stream->time_base.den); } + if (avContextTab[avContextIdx]->start_time != AV_NOPTS_VALUE) { pts -= 90000 * avContextTab[avContextIdx]->start_time / AV_TIME_BASE; } + if (pts & 0x8000000000000000ull) { pts = INVALID_PTS_VALUE; @@ -489,6 +498,7 @@ static int64_t calcPts(uint32_t avContextIdx, AVStream *stream, int64_t pts) { pts &= 0x01FFFFFFFF; // PES header can handle only 33 bit PTS } + return pts; } @@ -504,6 +514,7 @@ static char *searchMeta(void *metadata, char *ourTag) AVDictionaryEntry *tag = NULL; #endif int i = 0; + while (metadata_map[i] != NULL) { if (strcmp(ourTag, metadata_map[i]) == 0) @@ -522,6 +533,7 @@ static char *searchMeta(void *metadata, char *ourTag) } i++; } + return NULL; } @@ -540,22 +552,27 @@ static void FFMPEGThread(Context_t *context) //int64_t lastPts = -1; int64_t currentVideoPts = -1; int64_t currentAudioPts = -1; + /* lastVideoDts and lastAudioDts * used in isTSLiveMode */ int64_t lastVideoDts = -1; int64_t lastAudioDts = -1; + int64_t showtime = 0; int64_t bofcount = 0; //int32_t err = 0; AudioVideoOut_t avOut; + g_context = context; + SwrContext *swr = NULL; AVFrame *decoded_frame = NULL; int32_t out_sample_rate = 44100; int32_t out_channels = 2; uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO; uint32_t cAVIdx = 0; + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 34, 100) Mpeg4P2Context mpeg4p2_context; memset(&mpeg4p2_context, 0, sizeof(Mpeg4P2Context)); @@ -572,16 +589,17 @@ static void FFMPEGThread(Context_t *context) usleep(1000); } ffmpeg_printf(10, "Running!\n"); + int8_t isWaitingForFinish = 0; while (context && context->playback && context->playback->isPlaying) { - /* When user press PAUSE we call pause on AUDIO and VIDEO decoders, - * we will not wait here because we can still fill - * DVB drivers buffers at PAUSE time - * - * In the future we can add buffering queue before injection in to - * AUDIO, VIDEO decoders, so we can not wait here - */ + /* When user press PAUSE we call pause on AUDIO and VIDEO decoders, + * we will not wait here because we can still fill + * DVB drivers buffers at PAUSE time + * + * In the future we can add buffering queue before injection in to + * AUDIO, VIDEO decoders, so we can not wait here + */ #ifdef __sh__ //IF MOVIE IS PAUSED, WAIT if (context->playback->isPaused) @@ -592,6 +610,7 @@ static void FFMPEGThread(Context_t *context) continue; } #endif + if (context->playback->isSeeking) { ffmpeg_printf(10, "seeking\n"); @@ -599,7 +618,9 @@ static void FFMPEGThread(Context_t *context) usleep(10000); continue; } + getMutex(__FILE__, __FUNCTION__, __LINE__); + if (!context->playback || !context->playback->isPlaying) { releaseMutex(__FILE__, __FUNCTION__, __LINE__); @@ -648,6 +669,7 @@ static void FFMPEGThread(Context_t *context) { bofcount = 0; } + if (do_seek_target_seconds || do_seek_target_bytes) { int res = -1; @@ -685,11 +707,13 @@ static void FFMPEGThread(Context_t *context) } do_seek_target_seconds = 0; do_seek_target_bytes = 0; + restart_audio_resampling = 1; currentVideoPts = -1; currentAudioPts = -1; latestPts = 0; seek_target_flag = 0; + // flush streams uint32_t i = 0; for (i = 0; i < IPTV_AV_CONTEXT_MAX_NUM; i += 1) @@ -718,6 +742,7 @@ static void FFMPEGThread(Context_t *context) flv2mpeg4_context_reset(&flv2mpeg4_context); #endif } + int ffmpegStatus = 0; if (!isWaitingForFinish) { @@ -736,6 +761,7 @@ static void FFMPEGThread(Context_t *context) cAVIdx = 0; } } + if (!isWaitingForFinish && (ffmpegStatus = av_read_frame(avContextTab[cAVIdx], &packet)) == 0) { int64_t pts = 0; @@ -743,7 +769,9 @@ static void FFMPEGThread(Context_t *context) Track_t *videoTrack = NULL; Track_t *audioTrack = NULL; Track_t *subtitleTrack = NULL; + int32_t pid = avContextTab[cAVIdx]->streams[packet.stream_index]->id; + reset_finish_timeout(); if (avContextTab[cAVIdx]->streams[packet.stream_index]->discard != AVDISCARD_ALL) { @@ -751,10 +779,12 @@ static void FFMPEGThread(Context_t *context) { ffmpeg_err("error getting video track\n"); } + if (context->manager->audio->Command(context, MANAGER_GET_TRACK, &audioTrack) < 0) { ffmpeg_err("error getting audio track\n"); } + if (context->manager->subtitle->Command(context, MANAGER_GET_TRACK, &subtitleTrack) < 0) { ffmpeg_err("error getting subtitle track\n"); @@ -764,7 +794,9 @@ static void FFMPEGThread(Context_t *context) { ffmpeg_printf(1, "SKIP DISCARDED PACKET stream_index[%d] pid[%d]\n", packet.size, (int)packet.stream_index, pid); } + ffmpeg_printf(200, "packet.size %d - index %d\n", packet.size, pid); + if (videoTrack && (videoTrack->AVIdx == (int)cAVIdx) && (videoTrack->Id == pid)) { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 34, 100) @@ -799,11 +831,13 @@ static void FFMPEGThread(Context_t *context) uint8_t skipPacket = 0; currentVideoPts = videoTrack->pts = pts = calcPts(cAVIdx, videoTrack->stream, packet.pts); videoTrack->dts = dts = calcPts(cAVIdx, videoTrack->stream, packet.dts); + if ((currentVideoPts != INVALID_PTS_VALUE) && (currentVideoPts > latestPts)) { latestPts = currentVideoPts; update_max_injected_pts(latestPts); } + if (context->playback->isTSLiveMode) { if (dts != INVALID_PTS_VALUE) @@ -826,13 +860,16 @@ static void FFMPEGThread(Context_t *context) skipPacket = 1; } } + if (skipPacket) { wrapped_packet_unref(&packet); releaseMutex(__FILE__, __FUNCTION__, __LINE__); continue; } + ffmpeg_printf(200, "VideoTrack index = %d %lld\n", pid, currentVideoPts); + avOut.data = packet.data; avOut.len = packet.size; avOut.pts = pts; @@ -844,10 +881,12 @@ static void FFMPEGThread(Context_t *context) avOut.width = videoTrack->width; avOut.height = videoTrack->height; avOut.type = "video"; + if (avContextTab[cAVIdx]->iformat->flags & AVFMT_TS_DISCONT) { avOut.infoFlags = 1; // TS container } + if (Write(context->output->video->Write, context, &avOut, pts) < 0) { ffmpeg_err("writing data to video device failed\n"); @@ -859,11 +898,13 @@ static void FFMPEGThread(Context_t *context) uint8_t skipPacket = 0; currentAudioPts = audioTrack->pts = pts = calcPts(cAVIdx, audioTrack->stream, packet.pts); dts = calcPts(cAVIdx, audioTrack->stream, packet.dts); + if ((currentAudioPts != INVALID_PTS_VALUE) && (currentAudioPts > latestPts) && (!videoTrack)) { latestPts = currentAudioPts; update_max_injected_pts(latestPts); } + if (context->playback->isTSLiveMode) { if (dts != INVALID_PTS_VALUE) @@ -886,12 +927,14 @@ static void FFMPEGThread(Context_t *context) skipPacket = 1; } } + if (skipPacket) { wrapped_packet_unref(&packet); releaseMutex(__FILE__, __FUNCTION__, __LINE__); continue; } + pcmPrivateData_t pcmExtradata; pcmExtradata.channels = get_codecpar(audioTrack->stream)->channels; pcmExtradata.bits_per_coded_sample = get_codecpar(audioTrack->stream)->bits_per_coded_sample; @@ -899,13 +942,16 @@ static void FFMPEGThread(Context_t *context) pcmExtradata.bit_rate = get_codecpar(audioTrack->stream)->bit_rate; pcmExtradata.ffmpeg_codec_id = get_codecpar(audioTrack->stream)->codec_id; pcmExtradata.bResampling = restart_audio_resampling; + uint8_t *pAudioExtradata = get_codecpar(audioTrack->stream)->extradata; uint32_t audioExtradataSize = get_codecpar(audioTrack->stream)->extradata_size; + ffmpeg_printf(200, "AudioTrack index = %d\n", pid); if (audioTrack->inject_raw_pcm == 1) { ffmpeg_printf(200, "write audio raw pcm\n"); restart_audio_resampling = 0; + avOut.data = packet.data; avOut.len = packet.size; avOut.pts = pts; @@ -916,6 +962,7 @@ static void FFMPEGThread(Context_t *context) avOut.width = 0; avOut.height = 0; avOut.type = "audio"; + if (Write(context->output->audio->Write, context, &avOut, pts) < 0) { ffmpeg_err("(raw pcm) writing data to audio device failed\n"); @@ -924,6 +971,7 @@ static void FFMPEGThread(Context_t *context) else if (audioTrack->inject_as_pcm == 1 && audioTrack->avCodecCtx) { AVCodecContext *c = audioTrack->avCodecCtx; + if (restart_audio_resampling) { restart_audio_resampling = 0; @@ -948,6 +996,7 @@ static void FFMPEGThread(Context_t *context) { break; } + if (!decoded_frame) { decoded_frame = wrapped_frame_alloc(); @@ -968,10 +1017,12 @@ static void FFMPEGThread(Context_t *context) restart_audio_resampling = 1; break; } + if (ret >= 0) { packet.size = 0; } + ret = avcodec_receive_frame(c, decoded_frame); if (ret < 0) { @@ -993,8 +1044,10 @@ static void FFMPEGThread(Context_t *context) ffmpeg_err("avcodec_decode_audio4: %d\n", len); break; } + packet.data += len; packet.size -= len; + if (!got_frame) { continue; @@ -1018,13 +1071,16 @@ static void FFMPEGThread(Context_t *context) } out_sample_rate = *rate ? *rate : 44100; } + swr = swr_alloc(); out_channels = c->channels; + if (c->channel_layout == 0) { c->channel_layout = av_get_default_channel_layout(c->channels); } out_channel_layout = c->channel_layout; + uint8_t downmix = stereo_software_decoder && out_channels > 2 ? 1 : 0; #ifdef __sh__ // player2 won't play mono @@ -1038,12 +1094,15 @@ static void FFMPEGThread(Context_t *context) out_channel_layout = AV_CH_LAYOUT_STEREO_DOWNMIX; out_channels = 2; } + av_opt_set_int(swr, "in_channel_layout", c->channel_layout, 0); av_opt_set_int(swr, "out_channel_layout", out_channel_layout, 0); av_opt_set_int(swr, "in_sample_rate", c->sample_rate, 0); av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0); av_opt_set_int(swr, "in_sample_fmt", c->sample_fmt, 0); av_opt_set_int(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + + e = swr_init(swr); if (e < 0) { @@ -1053,6 +1112,7 @@ static void FFMPEGThread(Context_t *context) swr = NULL; } } + uint8_t *output[8] = {NULL}; int32_t in_samples = decoded_frame->nb_samples; int32_t out_samples = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + in_samples, out_sample_rate, c->sample_rate, AV_ROUND_UP); @@ -1068,8 +1128,10 @@ static void FFMPEGThread(Context_t *context) int64_t next_out_pts = av_rescale(swr_next_pts(swr, next_in_pts), ((AVStream *) audioTrack->stream)->time_base.den, ((AVStream *) audioTrack->stream)->time_base.num * (int64_t)out_sample_rate * c->sample_rate); + currentAudioPts = audioTrack->pts = pts = calcPts(cAVIdx, audioTrack->stream, next_out_pts); out_samples = swr_convert(swr, &output[0], out_samples, (const uint8_t **) &decoded_frame->data[0], in_samples); + ////////////////////////////////////////////////////////////////////// // Update pcmExtradata according to decode parameters pcmExtradata.channels = av_get_channel_layout_nb_channels(out_channel_layout); @@ -1081,9 +1143,12 @@ static void FFMPEGThread(Context_t *context) #else pcmExtradata.ffmpeg_codec_id = AV_CODEC_ID_PCM_S16LE; #endif + ////////////////////////////////////////////////////////////////////// + avOut.data = output[0]; avOut.len = out_samples * sizeof(int16_t) * out_channels; + avOut.pts = pts; avOut.extradata = (unsigned char *) &pcmExtradata; avOut.extralen = sizeof(pcmExtradata); @@ -1092,6 +1157,7 @@ static void FFMPEGThread(Context_t *context) avOut.width = 0; avOut.height = 0; avOut.type = "audio"; + if (!context->playback->BackWard && Write(context->output->audio->Write, context, &avOut, pts) < 0) { ffmpeg_err("writing data to audio device failed\n"); @@ -1103,6 +1169,7 @@ static void FFMPEGThread(Context_t *context) { ffmpeg_printf(200, "write audio aac\n"); ffmpeg_printf(200, ">>>>>>> %x %x %x %x %x %x %x\n", packet.data[0], packet.data[1], packet.data[2], packet.data[3], packet.data[4], packet.data[5], packet.data[6]); + avOut.data = packet.data; avOut.len = packet.size; avOut.pts = pts; @@ -1113,6 +1180,7 @@ static void FFMPEGThread(Context_t *context) avOut.width = 0; avOut.height = 0; avOut.type = "audio"; + if (!context->playback->BackWard && Write(context->output->audio->Write, context, &avOut, pts) < 0) { ffmpeg_err("(aac) writing data to audio device failed\n"); @@ -1130,6 +1198,7 @@ static void FFMPEGThread(Context_t *context) avOut.width = 0; avOut.height = 0; avOut.type = "audio"; + if (!context->playback->BackWard && Write(context->output->audio->Write, context, &avOut, pts) < 0) { ffmpeg_err("writing data to audio device failed\n"); @@ -1141,6 +1210,7 @@ static void FFMPEGThread(Context_t *context) int64_t duration = -1; pts = calcPts(cAVIdx, subtitleTrack->stream, packet.pts); AVStream *stream = subtitleTrack->stream; + if (packet.duration != 0) { // duration in milliseconds @@ -1151,6 +1221,7 @@ static void FFMPEGThread(Context_t *context) // duration in milliseconds duration = (int64_t)av_rescale(get_packet_duration(&packet), (int64_t)stream->time_base.num * 1000, stream->time_base.den); } + if (duration > 0) { SubtitleOut_t subOut; @@ -1171,11 +1242,13 @@ static void FFMPEGThread(Context_t *context) if (0 != ffmpegStatus) { static char errbuf[256]; + if (0 == av_strerror(ffmpegStatus, errbuf, sizeof(errbuf))) { /* In this way we inform user about error within the core */ printf("{\"log\":\"Frame read error: '%s'\"}\n", errbuf); } + /* if(ffmpegStatus == AVERROR(EAGAIN)) { @@ -1184,6 +1257,7 @@ static void FFMPEGThread(Context_t *context) */ ffmpegStatus = 0; } + if (!is_finish_timeout() && !context->playback->isTSLiveMode) { isWaitingForFinish = 1; @@ -1224,6 +1298,7 @@ static void FFMPEGThread(Context_t *context) printf("{\"log\":\"Loop mode: jump to the start.\"}\n"); } } + // av_read_frame failed ffmpeg_err("no data ->end of file reached ? \n"); wrapped_packet_unref(&packet); @@ -1241,14 +1316,17 @@ static void FFMPEGThread(Context_t *context) wrapped_packet_unref(&packet); releaseMutex(__FILE__, __FUNCTION__, __LINE__); } /* while */ + if (swr) { swr_free(&swr); } + if (decoded_frame) { wrapped_frame_free(&decoded_frame); } + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 34, 100) mpeg4p2_context_reset(&mpeg4p2_context); if (NULL != mpeg4p2_bsf_context) @@ -1256,6 +1334,7 @@ static void FFMPEGThread(Context_t *context) av_bitstream_filter_close(mpeg4p2_bsf_context); } #endif + hasPlayThreadStarted = 0; context->playback->isPlaying = 0; PlaybackDieNow(1); @@ -1301,13 +1380,16 @@ AVIOContext *container_ffmpeg_get_avio_context(char *filename, size_t avio_ctx_b { filename += 7; } + FILE *pFile = fopen(filename, "rb"); if (NULL == pFile) { return NULL; } + AVIOContext *avio_ctx = NULL; uint8_t *avio_ctx_buffer = NULL; + avio_ctx_buffer = av_malloc(avio_ctx_buffer_size); if (!avio_ctx_buffer) { @@ -1329,8 +1411,10 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int avContextTab[AVIdx] = avformat_alloc_context(); avContextTab[AVIdx]->interrupt_callback.callback = interrupt_cb; avContextTab[AVIdx]->interrupt_callback.opaque = context->playback; + #ifdef SAM_CUSTOM_IO - if (0 == strstr(filename, "://") || 0 == strncmp(filename, "file://", 7)) + if (0 == strstr(filename, "://") || + 0 == strncmp(filename, "file://", 7)) { AVIOContext *avio_ctx = container_ffmpeg_get_avio_context(filename, 4096); if (avio_ctx) @@ -1344,6 +1428,7 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int } } #endif + AVDictionary **pavio_opts = NULL; eRTMPProtoImplType rtmpProtoImplType = RTMP_NONE; uint8_t numOfRTMPImpl = 0; @@ -1352,6 +1437,7 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int filename = filename + 2; rtmpProtoImplType = RTMP_NATIVE; } + if (1 == rtmp_proto_impl) { rtmpProtoImplType = RTMP_NATIVE; @@ -1360,6 +1446,7 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int { rtmpProtoImplType = RTMP_LIBRTMP; } + if (0 == strncmp(filename, "rtmp://", 7) || 0 == strncmp(filename, "rtmpe://", 8) || 0 == strncmp(filename, "rtmps://", 8) || @@ -1373,6 +1460,7 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int void *opaque = NULL; const char *protoName = NULL; uint8_t haveNativeProto = 0; + while ((protoName = avio_enum_protocols(&opaque, 1))) { if (0 == strcmp("rtmp", protoName)) @@ -1392,6 +1480,7 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int haveNativeProto = 1; } } + if (haveNativeProto > 0) { if (numOfRTMPImpl > 1) // we have both @@ -1402,7 +1491,8 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int * unless uri contain param wich can be understandable * only by librtmp */ - if (strstr(filename, " token=") || strstr(filename, " jtv=")) + if (strstr(filename, " token=") || + strstr(filename, " jtv=")) { rtmpProtoImplType = RTMP_LIBRTMP; } @@ -1421,10 +1511,12 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int { rtmpProtoImplType = RTMP_LIBRTMP; } + if (RTMP_NATIVE == rtmpProtoImplType) { char *baseUri = strdup(filename); char *token = NULL; + // check if uri have additional params if ((token = strtok(baseUri, " ")) != NULL) { @@ -1512,11 +1604,13 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int } token = NULL; } + if (conn[0] != '\0') { av_dict_set(&avio_opts, "rtmp_conn", conn, 0); } free(conn); + if (swfUrl[0] != '\0') { if (swfVfy[0] == '1' || !strncasecmp(swfVfy, "true", 4)) @@ -1531,6 +1625,7 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int free(swfUrl); free(swfVfy); } + if (2 == haveNativeProto) { filename = malloc(strlen(baseUri) + 2 + 1); @@ -1546,7 +1641,8 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int } } } - else if (0 == strncmp(filename, "http://", 7) || 0 == strncmp(filename, "https://", 8)) + else if (0 == strncmp(filename, "http://", 7) || + 0 == strncmp(filename, "https://", 8)) { av_dict_set(&avio_opts, "timeout", "20000000", 0); //20sec av_dict_set(&avio_opts, "reconnect", "1", 0); @@ -1557,7 +1653,9 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int av_dict_set(&avio_opts, "reconnect_streamed", "1", 0); } } + pavio_opts = &avio_opts; + if ((err = avformat_open_input(&avContextTab[AVIdx], filename, fmt, pavio_opts)) != 0) { if (rtmp_proto_impl == 0 && //err == AVERROR_UNKNOWN && @@ -1568,12 +1666,15 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int err = avformat_open_input(&avContextTab[AVIdx], filename + 2, fmt, pavio_opts); // filename2 - another memory leak, and also only once, so does not matter } + if (err != 0) { char error[512]; + ffmpeg_err("avformat_open_input failed %d (%s)\n", err, filename); av_strerror(err, error, 512); fprintf(stderr, "{\"FF_ERROR\":{\"msg\":\"%s\",\"code\":%i}}\n", error, err); + if (avio_opts != NULL) { av_dict_free(&avio_opts); @@ -1582,22 +1683,29 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int return cERR_CONTAINER_FFMPEG_OPEN; } } + avContextTab[AVIdx]->iformat->flags |= AVFMT_SEEK_TO_PTS; avContextTab[AVIdx]->flags = AVFMT_FLAG_GENPTS; + printf("minimal Probe: %d\n", context->playback->noprobe); + if (context->playback->noprobe) { wrapped_set_max_analyze_duration(avContextTab[AVIdx], 1); } + ffmpeg_printf(20, "find_streaminfo\n"); + if (avformat_find_stream_info(avContextTab[AVIdx], NULL) < 0) { ffmpeg_err("Error avformat_find_stream_info\n"); } + //for buffered io if (avContextTab[AVIdx] != NULL && avContextTab[AVIdx]->pb != NULL && !context->playback->isTSLiveMode) { ffmpeg_real_read_org = avContextTab[AVIdx]->pb->read_packet; + if (0 == AVIdx && strstr(filename, "://") != 0 && strncmp(filename, "file://", 7) != 0) { if (ffmpeg_buf_size > 0 && ffmpeg_buf_size > FILLBUFDIFF + FILLBUFPAKET) @@ -1605,15 +1713,18 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int if (avContextTab[AVIdx] != NULL && avContextTab[AVIdx]->pb != NULL) { ffmpeg_buf = av_malloc(ffmpeg_buf_size); + if (ffmpeg_buf != NULL) { ffmpeg_printf(10, "buffer size=%d\n", ffmpeg_buf_size); + ffmpeg_read_org = avContextTab[AVIdx]->pb->read_packet; avContextTab[AVIdx]->pb->read_packet = ffmpeg_read; ffmpeg_seek_org = avContextTab[AVIdx]->pb->seek; avContextTab[AVIdx]->pb->seek = ffmpeg_seek; ffmpeg_buf_read = ffmpeg_buf; ffmpeg_buf_write = ffmpeg_buf; + //fill buffer ffmpeg_filler(context, -1, NULL, 0); ffmpeg_start_fillerTHREAD(context); @@ -1627,28 +1738,34 @@ int32_t container_ffmpeg_init_av_context(Context_t *context, char *filename, int } } //for buffered io (end) + return 0; } int32_t container_ffmpeg_init(Context_t *context, PlayFiles_t *playFilesNames) { //int32_t err = 0; + ffmpeg_printf(10, ">\n"); + if (playFilesNames == NULL) { ffmpeg_err("playFilesNames NULL\n"); return cERR_CONTAINER_FFMPEG_NULL; } + if (playFilesNames->szFirstFile == NULL) { ffmpeg_err("playFilesNames->szFirstFile NULL\n"); return cERR_CONTAINER_FFMPEG_NULL; } + if (context == NULL) { ffmpeg_err("context NULL\n"); return cERR_CONTAINER_FFMPEG_NULL; } + ffmpeg_printf(10, "filename %s\n", playFilesNames->szFirstFile); if (playFilesNames->szSecondFile) { @@ -1658,24 +1775,29 @@ int32_t container_ffmpeg_init(Context_t *context, PlayFiles_t *playFilesNames) avcodec_register_all(); av_register_all(); avformat_network_init(); + // SULGE DEBUG ENABLED // make ffmpeg silen // av_log_set_level(AV_LOG_DEBUG); av_log_set_callback(ffmpeg_silen_callback); + context->playback->abortRequested = 0; int32_t res = container_ffmpeg_init_av_context(context, playFilesNames->szFirstFile, 0); if (0 != res) { return res; } + if (playFilesNames->szSecondFile) { res = container_ffmpeg_init_av_context(context, playFilesNames->szSecondFile, 1); } + if (0 != res) { return res; } + terminating = 0; latestPts = 0; res = container_ffmpeg_update_tracks(context, playFilesNames->szFirstFile, 1); @@ -1687,35 +1809,45 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 Track_t *currAudioTrack = NULL; Track_t *currSubtitleTrack = NULL; uint32_t addedVideoTracksCount = 0; + if (terminating) { return cERR_CONTAINER_FFMPEG_NO_ERROR; } + getMutex(__FILE__, __FUNCTION__, __LINE__); + if (initial && context->manager->subtitle) { context->manager->subtitle->Command(context, MANAGER_GET_TRACK, &currSubtitleTrack); } + if (context->manager->audio) { context->manager->audio->Command(context, MANAGER_GET_TRACK, &currAudioTrack); } + if (context->manager->video) { context->manager->video->Command(context, MANAGER_INIT_UPDATE, NULL); } + if (context->manager->audio) { context->manager->audio->Command(context, MANAGER_INIT_UPDATE, NULL); } + #if 0 if (context->manager->subtitle) { context->manager->subtitle->Command(context, MANAGER_INIT_UPDATE, NULL); } #endif + ffmpeg_printf(20, "dump format\n"); av_dump_format(avContextTab[0], 0, filename, 0); + + uint32_t cAVIdx = 0; for (cAVIdx = 0; cAVIdx < IPTV_AV_CONTEXT_MAX_NUM; cAVIdx += 1) { @@ -1726,7 +1858,9 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 AVFormatContext *avContext = avContextTab[cAVIdx]; uint32_t *stream_index = NULL; uint32_t nb_stream_indexes = 0; + ffmpeg_printf(1, "cAVIdx[%d]: number of streams: %d\n", cAVIdx, avContext->nb_streams); + if (avContext->nb_programs > 0) { uint32_t n = 0; @@ -1764,6 +1898,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 } } } + uint32_t n = 0; for (n = 0; n < avContext->nb_streams; n++) { @@ -1771,6 +1906,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 AVStream *stream = avContext->streams[n]; int32_t version = 0; char *encoding = NULL; + if (nb_stream_indexes > 0 && stream_index != NULL) { uint32_t isStreamFromSelProg = 0; @@ -1783,6 +1919,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 break; } } + if (!isStreamFromSelProg) { stream->discard = AVDISCARD_ALL; @@ -1790,27 +1927,33 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 continue; // skip this stream } } + encoding = Codec2Encoding((int32_t)get_codecpar(stream)->codec_id, (int32_t)get_codecpar(stream)->codec_type, \ (uint8_t *)get_codecpar(stream)->extradata, \ (int)get_codecpar(stream)->extradata_size, \ (int)get_codecpar(stream)->profile, &version); + if (encoding != NULL && !strncmp(encoding, "A_IPCM", 6) && insert_pcm_as_lpcm) { encoding = "A_LPCM"; } + if (encoding != NULL) { ffmpeg_printf(1, "%d. encoding = %s - version %d\n", n, encoding, version); } + if (!stream->id) { stream->id = n; } + /* some values in track are unset and therefor copyTrack segfaults. * so set it by default to NULL! */ memset(&track, 0, sizeof(track)); track.AVIdx = cAVIdx; + switch (get_codecpar(stream)->codec_type) { case AVMEDIA_TYPE_VIDEO: @@ -1820,8 +1963,10 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 { track.type = eTypeES; track.version = version; + track.width = get_codecpar(stream)->width; track.height = get_codecpar(stream)->height; + /* We will return here PAR (Pixel Aspect Ratio) client need to calculate DAR(Display Aspect Ratio) * example: PAR 64:45 DAR 16:9 * Resolution 720x576 @@ -1835,15 +1980,19 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 track.aspect_ratio_num = get_codecpar(stream)->sample_aspect_ratio.num; track.aspect_ratio_den = get_codecpar(stream)->sample_aspect_ratio.den; } + track.extraData = get_codecpar(stream)->extradata; track.extraSize = get_codecpar(stream)->extradata_size; + track.aacbuf = 0; track.have_aacheader = -1; + AVRational rateRational = get_frame_rate(stream); if (rateRational.den != 0) { track.frame_rate = (uint32_t)(1000 * (int64_t)(rateRational.num) / (int64_t)(rateRational.den)); } + /* fixme: revise this */ if (track.frame_rate < 23970) { @@ -1853,6 +2002,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 { track.TimeScale = 1000; } + ffmpeg_printf(10, "bit_rate [%lld]\n", get_codecpar(stream)->bit_rate); ffmpeg_printf(10, "time_base.den [%d]\n", stream->time_base.den); ffmpeg_printf(10, "time_base.num [%d]\n", stream->time_base.num); @@ -1860,19 +2010,24 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 ffmpeg_printf(10, "height [%d]\n", get_codecpar(stream)->height); ffmpeg_printf(10, "frame_rate num [%d]\n", rateRational.num); ffmpeg_printf(10, "frame_rate den [%d]\n", rateRational.den); + ffmpeg_printf(10, "frame_rate [%u]\n", track.frame_rate); ffmpeg_printf(10, "TimeScale [%d]\n", track.TimeScale); + track.Name = "und"; track.Encoding = encoding; track.stream = stream; track.Id = ((AVStream *)(track.stream))->id; + track.duration = (int64_t)av_rescale(stream->duration, (int64_t)stream->time_base.num * 1000, stream->time_base.den); if (stream->duration == AV_NOPTS_VALUE || 0 == strncmp(avContext->iformat->name, "dash", 4)) { ffmpeg_printf(10, "Stream has no duration so we take the duration from context\n"); track.duration = (int64_t) avContext->duration / 1000; } + ffmpeg_printf(10, "duration [%lld]\n", track.duration); + if (context->manager->video) { if (get_codecpar(stream)->codec_id == AV_CODEC_ID_MPEG4) @@ -1907,20 +2062,26 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 { AVDictionaryEntry *lang; track.type = eTypeES; + lang = av_dict_get(stream->metadata, "language", NULL, 0); + track.Name = lang ? lang->value : "und"; + ffmpeg_printf(10, "Language %s\n", track.Name); + track.Encoding = encoding; track.stream = stream; track.Id = ((AVStream *)(track.stream))->id; track.aacbuf = 0; track.have_aacheader = -1; + track.duration = (int64_t)av_rescale(stream->duration, (int64_t)stream->time_base.num * 1000, stream->time_base.den); if (stream->duration == AV_NOPTS_VALUE) { ffmpeg_printf(10, "Stream has no duration so we take the duration from context\n"); track.duration = (int64_t) avContext->duration / 1000; } + if (!strncmp(encoding, "A_IPCM", 6) || !strncmp(encoding, "A_LPCM", 6)) { track.inject_as_pcm = 1; @@ -1928,7 +2089,9 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 if (track.avCodecCtx) { ffmpeg_printf(10, " Handle inject_as_pcm = %d\n", track.inject_as_pcm); + AVCodec *codec = avcodec_find_decoder(get_codecpar(stream)->codec_id); + int errorCode = avcodec_open2(track.avCodecCtx, codec, NULL); if (codec != NULL && !errorCode) { @@ -1950,6 +2113,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 track.aacbuflen = sizeof(marker) / sizeof(char); track.aacbuf = malloc(track.aacbuflen); memcpy(track.aacbuf, marker, track.aacbuflen); + ffmpeg_printf(10, "AV_CODEC_ID_AAC_LATM no extradata ACC header should be available in each frame\n"); track.have_aacheader = 1; } @@ -1966,6 +2130,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 track.aacbuflen = sizeof(marker) / sizeof(char); track.aacbuf = malloc(track.aacbuflen); memcpy(track.aacbuf, marker, track.aacbuflen); + ffmpeg_printf(10, "AV_CODEC_ID_AAC no extradata ACC header should be available in each frame\n"); track.have_aacheader = 1; } @@ -1974,6 +2139,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 ffmpeg_printf(10, "Create AAC ExtraData\n"); ffmpeg_printf(10, "get_codecpar(stream)->extradata_size %d\n", get_codecpar(stream)->extradata_size); //Hexdump(get_codecpar(stream)->extradata, get_codecpar(stream)->extradata_size); + /* extradata: 13 10 56 e5 9d 48 00 (anderen cops) object_type: 00010 2 = LC @@ -1988,12 +2154,14 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 ps = 0 0000000 */ + int32_t object_type = 2; // LC int32_t sample_index = aac_get_sample_rate_index(get_codecpar(stream)->sample_rate); int32_t chan_config = get_codecpar(stream)->channels - 1; ffmpeg_printf(1, "aac object_type %d\n", object_type); ffmpeg_printf(1, "aac sample_index %d\n", sample_index); ffmpeg_printf(1, "aac chan_config %d\n", chan_config); + if (get_codecpar(stream)->extradata_size >= 2) { MPEG4AudioConfig m4ac; @@ -2009,11 +2177,15 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 chan_config = m4ac.chan_config; } } + ffmpeg_printf(1, "aac object_type %d\n", object_type); ffmpeg_printf(1, "aac sample_index %d\n", sample_index); ffmpeg_printf(1, "aac chan_config %d\n", chan_config); + + // https://wiki.multimedia.cx/index.php/ADTS object_type -= 1; //ADTS - profile, the MPEG-4 Audio Object Type minus 1 + track.aacbuflen = AAC_HEADER_LENGTH; track.aacbuf = malloc(8); track.aacbuf[0] = 0xFF; @@ -2025,6 +2197,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 track.aacbuf[4] = 0x00; track.aacbuf[5] = 0x1F; track.aacbuf[6] = 0xFC; + //printf("AAC_HEADER -> "); //Hexdump(track.aacbuf,7); track.have_aacheader = 1; @@ -2035,6 +2208,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 ffmpeg_err("AV_CODEC_ID_AAC extradata not available\n"); } */ + } else if (get_codecpar(stream)->codec_id == AV_CODEC_ID_WMAV1 || get_codecpar(stream)->codec_id == AV_CODEC_ID_WMAV2 || @@ -2049,6 +2223,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 uint16_t depth = get_codecpar(stream)->bits_per_coded_sample; uint32_t codec_data_size = get_codecpar(stream)->extradata_size; uint8_t *codec_data_pointer = get_codecpar(stream)->extradata; + // type_specific_data #define WMA_VERSION_1 0x160 #define WMA_VERSION_2_9 0x161 @@ -2076,40 +2251,58 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 track.aacbuflen = 104 + get_codecpar(stream)->extradata_size; track.aacbuf = malloc(track.aacbuflen); memset(track.aacbuf, 0, track.aacbuflen); + uint8_t ASF_Stream_Properties_Object[16] = {0x91, 0x07, 0xDC, 0xB7, 0xB7, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}; + memcpy(track.aacbuf + 0, ASF_Stream_Properties_Object, 16); // ASF_Stream_Properties_Object memcpy(track.aacbuf + 16, &track.aacbuflen, 4); //FrameDateLength + uint32_t sizehi = 0; memcpy(track.aacbuf + 20, &sizehi, 4); // sizehi (not used) + uint8_t ASF_Audio_Media[16] = {0x40, 0x9E, 0x69, 0xF8, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}; + memcpy(track.aacbuf + 24, ASF_Audio_Media, 16); //ASF_Audio_Media + uint8_t ASF_Audio_Spread[16] = {0x50, 0xCD, 0xC3, 0xBF, 0x8F, 0x61, 0xCF, 0x11, 0x8B, 0xB2, 0x00, 0xAA, 0x00, 0xB4, 0xE2, 0x20}; + memcpy(track.aacbuf + 40, ASF_Audio_Spread, 16); //ASF_Audio_Spread + memset(track.aacbuf + 56, 0, 4); // time_offset (not used) memset(track.aacbuf + 60, 0, 4); // time_offset_hi (not used) + uint8_t type_specific_data_length = 18 + get_codecpar(stream)->extradata_size; memcpy(track.aacbuf + 64, &type_specific_data_length, 4); //type_specific_data_length + uint8_t error_correction_data_length = 8; memcpy(track.aacbuf + 68, &error_correction_data_length, 4); //error_correction_data_length + uint16_t flags = 1; // stream_number memcpy(track.aacbuf + 72, &flags, 2); //flags + uint32_t reserved = 0; memcpy(track.aacbuf + 74, &reserved, 4); // reserved + memcpy(track.aacbuf + 78, &codec_id, 2); //codec_id + uint16_t number_of_channels = get_codecpar(stream)->channels; memcpy(track.aacbuf + 80, &number_of_channels, 2); //number_of_channels + uint32_t samples_per_second = get_codecpar(stream)->sample_rate; ffmpeg_printf(1, "samples_per_second = %d\n", samples_per_second); memcpy(track.aacbuf + 82, &samples_per_second, 4); //samples_per_second + uint32_t average_number_of_bytes_per_second = get_codecpar(stream)->bit_rate / 8; ffmpeg_printf(1, "average_number_of_bytes_per_second = %d\n", average_number_of_bytes_per_second); memcpy(track.aacbuf + 86, &average_number_of_bytes_per_second, 4); //average_number_of_bytes_per_second + uint16_t block_alignment = get_codecpar(stream)->block_align; ffmpeg_printf(1, "block_alignment = %d\n", block_alignment); memcpy(track.aacbuf + 90, &block_alignment, 2); //block_alignment + #if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32)) enum AVSampleFormat sample_fmt = get_codecpar(stream)->format; #else @@ -2118,12 +2311,15 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 uint16_t bits_per_sample = sample_fmt >= 0 ? (sample_fmt + 1) * 8 : 8; ffmpeg_printf(1, "bits_per_sample = %d (%d)\n", bits_per_sample, sample_fmt); memcpy(track.aacbuf + 92, &bits_per_sample, 2); //bits_per_sample + memcpy(track.aacbuf + 94, &get_codecpar(stream)->extradata_size, 2); //bits_per_sample + memcpy(track.aacbuf + 96, get_codecpar(stream)->extradata, get_codecpar(stream)->extradata_size); #else track.aacbuflen = 18 + get_codecpar(stream)->extradata_size; track.aacbuf = malloc(track.aacbuflen); memset(track.aacbuf, 0, track.aacbuflen); + uint8_t *data = track.aacbuf; /* codec tag */ *(data++) = codec_id & 0xff; @@ -2155,10 +2351,13 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 #endif ffmpeg_printf(1, "aacbuf:\n"); //Hexdump(track.aacbuf, track.aacbuflen); + //ffmpeg_printf(1, "priv_data:\n"); //Hexdump(get_codecpar(stream)->priv_data, track.aacbuflen); + track.have_aacheader = 1; } + if (context->manager->audio) { ffmpeg_printf(1, "cAVIdx[%d]: MANAGER_ADD track AUDIO\n"); @@ -2190,26 +2389,34 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 { AVDictionaryEntry *lang = NULL; memset(&track, 0, sizeof(track)); + ffmpeg_printf(10, "CODEC_TYPE_SUBTITLE %d\n", get_codecpar(stream)->codec_type); + lang = av_dict_get(stream->metadata, "language", NULL, 0); track.Name = lang ? lang->value : "und"; ffmpeg_printf(10, "Language %s\n", track.Name); + track.Encoding = encoding; track.stream = stream; track.Id = ((AVStream *)(track.stream))->id; track.duration = (int64_t)av_rescale(stream->duration, (int64_t)stream->time_base.num * 1000, stream->time_base.den); + if (stream->duration == AV_NOPTS_VALUE) { ffmpeg_printf(10, "Stream has no duration so we take the duration from context\n"); track.duration = (int64_t) avContext->duration / 1000; } + track.extraData = get_codecpar(stream)->extradata; track.extraSize = get_codecpar(stream)->extradata_size; + ffmpeg_printf(1, "subtitle codec %d\n", get_codecpar(stream)->codec_id); ffmpeg_printf(1, "subtitle width %d\n", get_codecpar(stream)->width); ffmpeg_printf(1, "subtitle height %d\n", get_codecpar(stream)->height); ffmpeg_printf(1, "subtitle stream %p\n", stream); + ffmpeg_printf(10, "FOUND SUBTITLE %s\n", track.Name); + if (context->manager->subtitle->Command(context, MANAGER_ADD, &track) < 0) { ffmpeg_err("failed to add subtitle track %d\n", n); @@ -2228,11 +2435,13 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 } } /* for */ } + if (context->manager->audio) { Track_t *Tracks = NULL; int32_t TrackCount = 0; int32_t selTrackIdx = -1; + context->manager->audio->Command(context, MANAGER_REF_LIST, &Tracks); context->manager->audio->Command(context, MANAGER_REF_LIST_SIZE, &TrackCount); if (Tracks && TrackCount) @@ -2242,14 +2451,17 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 { if (Tracks[i].pending || Tracks[i].Id < 0) continue; + if (selTrackIdx == -1) selTrackIdx = i; + if (currAudioTrack && currAudioTrack->Id == Tracks[i].Id) { selTrackIdx = i; break; } } + if (selTrackIdx > -1) { ((AVStream *)Tracks[selTrackIdx].stream)->discard = AVDISCARD_DEFAULT; @@ -2260,6 +2472,7 @@ int32_t container_ffmpeg_update_tracks(Context_t *context, char *filename, int32 } } } + releaseMutex(__FILE__, __FUNCTION__, __LINE__); return cERR_CONTAINER_FFMPEG_NO_ERROR; } @@ -2269,7 +2482,9 @@ static int32_t container_ffmpeg_play(Context_t *context) int32_t error = 0; int32_t ret = 0; pthread_attr_t attr; + ffmpeg_printf(10, "\n"); + if (context && context->playback && context->playback->isPlaying) { ffmpeg_printf(10, "is Playing\n"); @@ -2278,19 +2493,23 @@ static int32_t container_ffmpeg_play(Context_t *context) { ffmpeg_printf(10, "is NOT Playing\n"); } + if (hasPlayThreadStarted == 0) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if ((error = pthread_create(&PlayThread, &attr, (void *)&FFMPEGThread, context)) != 0) { ffmpeg_printf(10, "Error creating thread, error:%d:%s\n", error, strerror(error)); + hasPlayThreadStarted = 0; ret = cERR_CONTAINER_FFMPEG_ERR; } else { ffmpeg_printf(10, "Created thread\n"); + hasPlayThreadStarted = 1; } } @@ -2299,6 +2518,7 @@ static int32_t container_ffmpeg_play(Context_t *context) ffmpeg_printf(10, "A thread already exists!\n"); ret = cERR_CONTAINER_FFMPEG_ERR; } + ffmpeg_printf(10, "exiting with value %d\n", ret); return ret; } @@ -2311,16 +2531,20 @@ static int32_t container_ffmpeg_stop(Context_t *context) * in this case, ffmpeg thread will not be terminated * and causes in most cases a segfault */ + ffmpeg_printf(10, "\n"); + if (context->playback) { context->playback->isPlaying = 0; } + while ((hasPlayThreadStarted != 0) && (--wait_time) > 0) { ffmpeg_printf(10, "Waiting for ffmpeg thread to terminate itself, will try another %d times\n", wait_time); usleep(100000); } + if (wait_time == 0) { /* force close */ @@ -2331,10 +2555,14 @@ static int32_t container_ffmpeg_stop(Context_t *context) */ return ret; } + hasPlayThreadStarted = 0; terminating = 1; + getMutex(__FILE__, __FUNCTION__, __LINE__); + free_all_stored_avcodec_context(); + uint32_t i = 0; for (i = 0; i < IPTV_AV_CONTEXT_MAX_NUM; i += 1) { @@ -2360,13 +2588,17 @@ static int32_t container_ffmpeg_stop(Context_t *context) break; } } + if (avio_opts != NULL) { av_dict_free(&avio_opts); } + avformat_network_deinit(); ffmpeg_buf_free(); + releaseMutex(__FILE__, __FUNCTION__, __LINE__); + ffmpeg_printf(10, "ret %d\n", ret); return ret; } @@ -2375,19 +2607,25 @@ static int32_t container_ffmpeg_seek_bytes(off_t pos) { int32_t flag = AVSEEK_FLAG_BYTE; off_t current_pos = avio_tell(avContextTab[0]->pb); + ffmpeg_printf(20, "seeking to position %lld (bytes)\n", pos); + if (current_pos > pos) { flag |= AVSEEK_FLAG_BACKWARD; } + if (avformat_seek_file(avContextTab[0], -1, INT64_MIN, pos, INT64_MAX, flag) < 0) { ffmpeg_err("Error seeking\n"); return cERR_CONTAINER_FFMPEG_ERR; } + ffmpeg_printf(30, "current_pos after seek %lld\n", avio_tell(avContextTab[0]->pb)); + return cERR_CONTAINER_FFMPEG_NO_ERROR; } + #if 0 //unused /* seeking relative to a given byteposition N seconds ->for reverse playback needed */ static int32_t container_ffmpeg_seek_rel(Context_t *context, off_t pos, int64_t pts, int64_t sec) @@ -2396,9 +2634,12 @@ static int32_t container_ffmpeg_seek_rel(Context_t *context, off_t pos, int64_t Track_t *audioTrack = NULL; Track_t *current = NULL; seek_target_flag = 0; + ffmpeg_printf(10, "seeking %f sec relativ to %lld\n", sec, pos); + context->manager->video->Command(context, MANAGER_GET_TRACK, &videoTrack); context->manager->audio->Command(context, MANAGER_GET_TRACK, &audioTrack); + if (videoTrack != NULL) { current = videoTrack; @@ -2407,23 +2648,28 @@ static int32_t container_ffmpeg_seek_rel(Context_t *context, off_t pos, int64_t { current = audioTrack; } + if (current == NULL) { ffmpeg_err("no track avaibale to seek\n"); return cERR_CONTAINER_FFMPEG_ERR; } + if (pos == -1) { pos = avio_tell(avContextTab[0]->pb); } + if (pts == -1) { pts = current->pts; } + if (sec < 0) { seek_target_flag |= AVSEEK_FLAG_BACKWARD; } + ffmpeg_printf(10, "iformat->flags %d\n", avContextTab[0]->iformat->flags); #if defined(TS_BYTES_SEEKING) && TS_BYTES_SEEKING if (avContextTab[0]->iformat->flags & AVFMT_TS_DISCONT) @@ -2437,41 +2683,53 @@ static int32_t container_ffmpeg_seek_rel(Context_t *context, off_t pos, int64_t { sec *= 180000; } + pos += sec; + if (pos < 0) { ffmpeg_err("end of file reached\n"); releaseMutex(__FILE__, __FUNCTION__, __LINE__); return cERR_CONTAINER_FFMPEG_END_OF_FILE; } + ffmpeg_printf(10, "1. seeking to position %lld bytes ->sec %f\n", pos, sec); + seek_target_bytes = pos; do_seek_target_bytes = 1; + return pos; } else #endif { sec += pts / 90000; + if (sec < 0) { sec = 0; } + ffmpeg_printf(10, "2. seeking to position %f sec ->time base %f %d\n", sec, av_q2d(((AVStream *) current->stream)->time_base), AV_TIME_BASE); + seek_target_seconds = sec * AV_TIME_BASE; do_seek_target_seconds = 1; } + releaseMutex(__FILE__, __FUNCTION__, __LINE__); return cERR_CONTAINER_FFMPEG_NO_ERROR; } #endif + static int32_t container_ffmpeg_seek(Context_t *context, int64_t sec, uint8_t absolute) { Track_t *videoTrack = NULL; Track_t *audioTrack = NULL; // Track_t *current = NULL; seek_target_flag = 0; + sec *= AV_TIME_BASE; + if (!absolute) { ffmpeg_printf(10, "seeking %lld sec\n", sec / AV_TIME_BASE); @@ -2497,9 +2755,12 @@ static int32_t container_ffmpeg_seek(Context_t *context, int64_t sec, uint8_t ab sec = 0; } } + ffmpeg_printf(10, "goto %lld sec\n", sec / AV_TIME_BASE); + context->manager->video->Command(context, MANAGER_GET_TRACK, &videoTrack); context->manager->audio->Command(context, MANAGER_GET_TRACK, &audioTrack); + if (!videoTrack && !audioTrack) { ffmpeg_err("no track available to seek\n"); @@ -2526,11 +2787,13 @@ static int32_t container_ffmpeg_seek(Context_t *context, int64_t sec, uint8_t ab { seek_target_flag |= AVSEEK_FLAG_BACKWARD; } + if (!context->playback || !context->playback->isPlaying) { releaseMutex(__FILE__, __FUNCTION__, __LINE__); return cERR_CONTAINER_FFMPEG_NO_ERROR; } + ffmpeg_printf(10, "iformat->flags 0x%08x\n", avContextTab[0]->iformat->flags); #if defined(TS_BYTES_SEEKING) && TS_BYTES_SEEKING if (avContextTab[0]->iformat->flags & AVFMT_TS_DISCONT) @@ -2541,10 +2804,13 @@ static int32_t container_ffmpeg_seek(Context_t *context, int64_t sec, uint8_t ab * seeking per HTTP does still not work very good. forward seeks everytime * about 10 seconds, backward does not work. */ + getMutex(__FILE__, __FUNCTION__, __LINE__); off_t pos = avio_tell(avContextTab[0]->pb); releaseMutex(__FILE__, __FUNCTION__, __LINE__); + ffmpeg_printf(10, "pos %lld %lld\n", pos, avContextTab[0]->bit_rate); + if (avContextTab[0]->bit_rate) { sec *= avContextTab[0]->bit_rate / 8; @@ -2554,12 +2820,16 @@ static int32_t container_ffmpeg_seek(Context_t *context, int64_t sec, uint8_t ab { sec *= 180000; } + pos = sec; + if (pos < 0) { pos = 0; } + ffmpeg_printf(10, "1. seeking to position %lld bytes ->sec %lld\n", pos / AV_TIME_BASE, sec / AV_TIME_BASE); + seek_target_bytes = pos / AV_TIME_BASE; do_seek_target_bytes = 1; } @@ -2569,6 +2839,7 @@ static int32_t container_ffmpeg_seek(Context_t *context, int64_t sec, uint8_t ab seek_target_seconds = sec; do_seek_target_seconds = 1; } + return cERR_CONTAINER_FFMPEG_NO_ERROR; } @@ -2578,13 +2849,16 @@ static int32_t container_ffmpeg_get_length(Context_t *context, int64_t *length) Track_t *videoTrack = NULL; Track_t *audioTrack = NULL; Track_t *current = NULL; + if (length == NULL) { ffmpeg_err("null pointer passed\n"); return cERR_CONTAINER_FFMPEG_ERR; } + context->manager->video->Command(context, MANAGER_GET_TRACK, &videoTrack); context->manager->audio->Command(context, MANAGER_GET_TRACK, &audioTrack); + if (videoTrack != NULL) { current = videoTrack; @@ -2593,7 +2867,9 @@ static int32_t container_ffmpeg_get_length(Context_t *context, int64_t *length) { current = audioTrack; } + *length = 0; + if (current != NULL) { if (current->duration == 0) @@ -2617,6 +2893,7 @@ static int32_t container_ffmpeg_get_length(Context_t *context, int64_t *length) return cERR_CONTAINER_FFMPEG_ERR; } } + return cERR_CONTAINER_FFMPEG_NO_ERROR; } @@ -2628,6 +2905,7 @@ static int32_t container_ffmpeg_switch_audio(Context_t *context, int32_t *arg __ { Track_t *Tracks = NULL; int32_t TrackCount = 0; + context->manager->audio->Command(context, MANAGER_REF_LIST, &Tracks); context->manager->audio->Command(context, MANAGER_REF_LIST_SIZE, &TrackCount); if (Tracks && TrackCount) @@ -2640,6 +2918,7 @@ static int32_t container_ffmpeg_switch_audio(Context_t *context, int32_t *arg __ } } releaseMutex(__FILE__, __FUNCTION__, __LINE__); + /* Hellmaster1024: nothing to do here! */ int64_t sec = -1; context->playback->Command(context, PLAYBACK_SEEK, (void *)&sec); @@ -2649,6 +2928,7 @@ static int32_t container_ffmpeg_switch_audio(Context_t *context, int32_t *arg __ static int32_t container_ffmpeg_switch_subtitle(Context_t *context, int32_t *arg __attribute__((unused))) { ffmpeg_printf(10, "track %d\n", *arg); + /* This is made to flush inside the buffer because * subtitles frame was already read and ignored * we seek to force ffmpeg to read once again the same data @@ -2672,7 +2952,9 @@ static int32_t container_ffmpeg_get_info(Context_t *context, char **infoString) Track_t *videoTrack = NULL; Track_t *audioTrack = NULL; char *meta = NULL; + ffmpeg_printf(20, ">\n"); + if (avContextTab[0] != NULL) { if ((infoString == NULL) || (*infoString == NULL)) @@ -2680,9 +2962,12 @@ static int32_t container_ffmpeg_get_info(Context_t *context, char **infoString) ffmpeg_err("infostring NULL\n"); return cERR_CONTAINER_FFMPEG_ERR; } + ffmpeg_printf(20, "%s\n", *infoString); + context->manager->video->Command(context, MANAGER_GET_TRACK, &videoTrack); context->manager->audio->Command(context, MANAGER_GET_TRACK, &audioTrack); + if ((meta = searchMeta(avContextTab[0]->metadata, *infoString)) == NULL) { if (audioTrack != NULL) @@ -2690,12 +2975,14 @@ static int32_t container_ffmpeg_get_info(Context_t *context, char **infoString) AVStream *stream = audioTrack->stream; meta = searchMeta(stream->metadata, *infoString); } + if ((meta == NULL) && (videoTrack != NULL)) { AVStream *stream = videoTrack->stream; meta = searchMeta(stream->metadata, *infoString); } } + if (meta != NULL) { *infoString = strdup(meta); @@ -2786,7 +3073,9 @@ static int container_ffmpeg_get_metadata(Context_t * context, char ***p) static int32_t Command(Context_t *context, ContainerCmd_t command, void *argument) { int ret = cERR_CONTAINER_FFMPEG_NO_ERROR; + ffmpeg_printf(50, "Command %d\n", command); + if (command != CONTAINER_SET_BUFFER_SEEK_TIME && command != CONTAINER_SET_BUFFER_SIZE && command != CONTAINER_GET_BUFFER_SIZE && @@ -2796,6 +3085,7 @@ static int32_t Command(Context_t *context, ContainerCmd_t command, void *argumen { return cERR_CONTAINER_FFMPEG_ERR; } + switch (command) { case CONTAINER_INIT: @@ -2878,6 +3168,7 @@ static int32_t Command(Context_t *context, ContainerCmd_t command, void *argumen ret = cERR_CONTAINER_FFMPEG_ERR; break; } + ffmpeg_printf(50, "exiting with value %d\n", ret); return ret; } diff --git a/libeplayer3-arm/container/flv2mpeg4_ffmpeg.c b/libeplayer3-arm/container/flv2mpeg4_ffmpeg.c index 8f72216..cc00144 100644 --- a/libeplayer3-arm/container/flv2mpeg4_ffmpeg.c +++ b/libeplayer3-arm/container/flv2mpeg4_ffmpeg.c @@ -5,6 +5,7 @@ #include "flv2mpeg4/flv2mpeg4.h" + typedef struct { flv2mpeg4_CTX *ctx; @@ -15,6 +16,7 @@ typedef struct Track_t *track; } Flv2Mpeg4Context; + static int flv2mpeg4_context_write_packet_cb(void *usr_data, int keyframe, int pts, const uint8_t *buf, int size) { Flv2Mpeg4Context *ctx = usr_data; @@ -22,6 +24,7 @@ static int flv2mpeg4_context_write_packet_cb(void *usr_data, int keyframe, int p { return -1; } + AudioVideoOut_t avOut; avOut.data = (char *)buf; avOut.len = size; @@ -34,10 +37,12 @@ static int flv2mpeg4_context_write_packet_cb(void *usr_data, int keyframe, int p avOut.width = ctx->track->width; avOut.height = ctx->track->height; avOut.type = "video"; + if (Write(ctx->out_ctx->output->video->Write, ctx->out_ctx, &avOut, avOut.pts) < 0) { ffmpeg_err("writing data to video device failed\n"); } + return 0; } @@ -48,10 +53,12 @@ static int flv2mpeg4_context_write_extradata_cb(void *usr_data, int width, int h { return -1; } + free(ctx->extradata); ctx->extradata = malloc(extradatasize); memcpy(ctx->extradata, extradata, extradatasize); ctx->extradatasize = extradatasize; + return 0; } @@ -59,6 +66,7 @@ static void flv2mpeg4_context_reset(Flv2Mpeg4Context *context) { if (context == NULL || context->ctx == NULL) return; + flv2mpeg4_set_frame(context->ctx, 0, 0); } @@ -69,14 +77,19 @@ static int flv2mpeg4_write_packet(Context_t *out_ctx, Flv2Mpeg4Context *mpeg4p2_ mpeg4p2_ctx->ctx = flv2mpeg4_init_ctx(mpeg4p2_ctx, track->width, track->height, flv2mpeg4_context_write_packet_cb, flv2mpeg4_context_write_extradata_cb); flv2mpeg4_prepare_extra_data(mpeg4p2_ctx->ctx); } + *pts_current = track->pts = calcPts(cAVIdx, track->stream, pkt->pts); if ((*pts_current > *pts_latest) && (*pts_current != INVALID_PTS_VALUE)) { *pts_latest = *pts_current; } track->dts = calcPts(cAVIdx, track->stream, pkt->dts); + mpeg4p2_ctx->out_ctx = out_ctx; mpeg4p2_ctx->track = track; + uint32_t time_ms = (uint32_t)(track->pts / 90); + return flv2mpeg4_process_flv_packet(mpeg4p2_ctx->ctx, 0, pkt->data, pkt->size, time_ms); } + diff --git a/libeplayer3-arm/container/mpeg4p2_ffmpeg.c b/libeplayer3-arm/container/mpeg4p2_ffmpeg.c index 74a5559..0565912 100644 --- a/libeplayer3-arm/container/mpeg4p2_ffmpeg.c +++ b/libeplayer3-arm/container/mpeg4p2_ffmpeg.c @@ -14,6 +14,7 @@ typedef struct AVPacket *second_ip_frame; } Mpeg4P2Context; + static void set_packet(AVPacket **pkt_dest, AVPacket *pkt_src) { if (pkt_dest == NULL) @@ -82,6 +83,7 @@ static void mpeg4p2_context_reset(Mpeg4P2Context *context) av_free(context->second_ip_frame); } context->second_ip_frame = NULL; + context->b_frames_count = 0; context->first_ip_frame_written = 0; context->packet_duration = 0; @@ -95,6 +97,7 @@ static void mpeg4p2_write(Context_t *ctx, Track_t *track, int avContextIdx, int6 *pts_latest = *pts_current; } track->dts = calcPts(avContextIdx, track->stream, pkt->dts); + AudioVideoOut_t avOut; avOut.data = pkt->data; avOut.len = pkt->size; @@ -107,6 +110,7 @@ static void mpeg4p2_write(Context_t *ctx, Track_t *track, int avContextIdx, int6 avOut.width = track->width; avOut.height = track->height; avOut.type = "video"; + if (Write(ctx->output->video->Write, ctx, &avOut, avOut.pts) < 0) { ffmpeg_err("writing data to video device failed\n"); @@ -206,3 +210,4 @@ static int mpeg4p2_write_packet(Context_t *ctx, Mpeg4P2Context *mpeg4p2_ctx, Tra } return 0; } + diff --git a/libeplayer3-arm/container/wrapped_ffmpeg.c b/libeplayer3-arm/container/wrapped_ffmpeg.c index 3ca4738..2bf6bb7 100644 --- a/libeplayer3-arm/container/wrapped_ffmpeg.c +++ b/libeplayer3-arm/container/wrapped_ffmpeg.c @@ -121,9 +121,11 @@ int store_avcodec_context(AVCodecContext *avCodecCtx __attribute__((unused)), ui { return -1; } + memset(ptr, 0x00, sizeof(CodecCtxStoreItem_t)); ptr->next = g_codecCtxStoreListHead; g_codecCtxStoreListHead = ptr; + return 0; } #else @@ -144,6 +146,7 @@ static AVCodecContext *wrapped_avcodec_get_context(uint32_t cAVIdx, AVStream *st fprintf(stderr, "context3 alloc for stream %d failed\n", (int)stream->id); return NULL; } + if (avcodec_parameters_to_context(avCodecCtx, stream->codecpar) < 0) { fprintf(stderr, "parameters to context for stream %d failed\n", (int)stream->id); @@ -151,8 +154,10 @@ static AVCodecContext *wrapped_avcodec_get_context(uint32_t cAVIdx, AVStream *st return NULL; } av_codec_set_pkt_timebase(avCodecCtx, stream->time_base); + store_avcodec_context(avCodecCtx, cAVIdx, stream->id); } + return avCodecCtx; #else return stream->codec; diff --git a/libeplayer3-arm/external/ffmpeg/get_bits.h b/libeplayer3-arm/external/ffmpeg/get_bits.h index b0f49e3..e40e201 100644 --- a/libeplayer3-arm/external/ffmpeg/get_bits.h +++ b/libeplayer3-arm/external/ffmpeg/get_bits.h @@ -100,9 +100,11 @@ typedef struct GetBitContext unsigned int name ## _index = (gb)->index; \ unsigned int av_unused name ## _cache + #define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) #define BITS_AVAILABLE(name, gb) 1 + #define CLOSE_READER(name, gb) (gb)->index = name ## _index # ifdef LONG_BITSTREAM_READER @@ -123,6 +125,7 @@ typedef struct GetBitContext #endif + #ifdef BITSTREAM_READER_LE # define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) @@ -139,6 +142,7 @@ typedef struct GetBitContext #define SKIP_COUNTER(name, gb, num) name ## _index += (num) + #define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) #define SKIP_BITS(name, gb, num) \ @@ -282,6 +286,7 @@ static inline unsigned int get_bits1(GetBitContext *s) #endif index++; s->index = index; + return result; } @@ -349,6 +354,7 @@ static inline int get_sbits_long(GetBitContext *s, int n) /* sign_extend(x, 0) is undefined */ if (!n) return 0; + return sign_extend(get_bits_long(s, n), n); } @@ -387,18 +393,22 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, { int buffer_size; int ret = 0; + if (bit_size >= INT_MAX - 7 || bit_size < 0 || !buffer) { bit_size = 0; buffer = NULL; ret = AVERROR_INVALIDDATA; } + buffer_size = (bit_size + 7) >> 3; + s->buffer = buffer; s->size_in_bits = bit_size; s->size_in_bits_plus8 = bit_size + 8; s->buffer_end = buffer + buffer_size; s->index = 0; + return ret; } @@ -500,6 +510,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) SKIP_BITS(name, gb, n); \ } while (0) + static inline int decode012(GetBitContext *gb) { int n; @@ -527,12 +538,14 @@ static inline int skip_1stop_8data_bits(GetBitContext *gb) { if (get_bits_left(gb) <= 0) return AVERROR_INVALIDDATA; + while (get_bits1(gb)) { skip_bits(gb, 8); if (get_bits_left(gb) <= 0) return AVERROR_INVALIDDATA; } + return 0; } diff --git a/libeplayer3-arm/external/ffmpeg/latmenc.h b/libeplayer3-arm/external/ffmpeg/latmenc.h index 8e6a847..e5d3345 100644 --- a/libeplayer3-arm/external/ffmpeg/latmenc.h +++ b/libeplayer3-arm/external/ffmpeg/latmenc.h @@ -42,3 +42,4 @@ int latmenc_decode_extradata(LATMContext *ctx, uint8_t *buf, int size); int latmenc_write_packet(LATMContext *ctx, uint8_t *data, int size, uint8_t *extradata, int extradata_size); #endif /* AVCODEC_LATMENC_H */ + diff --git a/libeplayer3-arm/external/ffmpeg/put_bits.h b/libeplayer3-arm/external/ffmpeg/put_bits.h index f99cfac..40cc722 100644 --- a/libeplayer3-arm/external/ffmpeg/put_bits.h +++ b/libeplayer3-arm/external/ffmpeg/put_bits.h @@ -54,6 +54,7 @@ static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, buffer_size = 0; buffer = NULL; } + s->size_in_bits = 8 * buffer_size; s->buf = buffer; s->buf_end = s->buf + buffer_size; @@ -73,6 +74,7 @@ static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer, int buffer_size) { av_assert0(8 * buffer_size > s->size_in_bits); + s->buf_end = buffer + buffer_size; s->buf_ptr = buffer + (s->buf_ptr - s->buf); s->buf = buffer; @@ -154,9 +156,12 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value) { unsigned int bit_buf; int bit_left; + av_assert2(n <= 31 && value < (1U << n)); + bit_buf = s->bit_buf; bit_left = s->bit_left; + /* XXX: optimize */ #ifdef BITSTREAM_WRITER_LE bit_buf |= value << (32 - bit_left); @@ -200,6 +205,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value) bit_buf = value; } #endif + s->bit_buf = bit_buf; s->bit_left = bit_left; } @@ -207,6 +213,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value) static inline void put_sbits(PutBitContext *pb, int n, int32_t value) { av_assert2(n >= 0 && n <= 31); + put_bits(pb, n, av_mod_uintp2(value, n)); } diff --git a/libeplayer3-arm/external/ffmpeg/src/bitstream.c b/libeplayer3-arm/external/ffmpeg/src/bitstream.c index 8c0f795..c992273 100644 --- a/libeplayer3-arm/external/ffmpeg/src/bitstream.c +++ b/libeplayer3-arm/external/ffmpeg/src/bitstream.c @@ -31,6 +31,7 @@ #include #include + void avpriv_align_put_bits(PutBitContext *s) { put_bits(s, s->bit_left & 7, 0); @@ -52,9 +53,12 @@ void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length) int words = length >> 4; int bits = length & 15; int i; + if (length == 0) return; + av_assert0(length <= put_bits_left(pb)); + if (words < 16 || put_bits_count(pb) & 7) { for (i = 0; i < words; i++) @@ -68,5 +72,7 @@ void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length) memcpy(put_bits_ptr(pb), src + i, 2 * words - i); skip_put_bytes(pb, 2 * words - i); } + put_bits(pb, bits, AV_RB16(src + 2 * words) >> (16 - bits)); } + diff --git a/libeplayer3-arm/external/ffmpeg/src/latmenc.c b/libeplayer3-arm/external/ffmpeg/src/latmenc.c index 86a11f4..9c13c32 100644 --- a/libeplayer3-arm/external/ffmpeg/src/latmenc.c +++ b/libeplayer3-arm/external/ffmpeg/src/latmenc.c @@ -38,9 +38,11 @@ #define latmenc_err(fmt, x...) #endif + int latmenc_decode_extradata(LATMContext *ctx, uint8_t *buf, int size) { MPEG4AudioConfig m4ac; + if (size > MAX_EXTRADATA_SIZE) { latmenc_err("Extradata is larger than currently supported.\n"); @@ -49,6 +51,7 @@ int latmenc_decode_extradata(LATMContext *ctx, uint8_t *buf, int size) ctx->off = avpriv_mpeg4audio_get_config(&m4ac, buf, size * 8, 1); if (ctx->off < 0) return ctx->off; + if (ctx->object_type == AOT_ALS && (ctx->off & 7)) { // as long as avpriv_mpeg4audio_get_config works correctly this is impossible @@ -56,6 +59,7 @@ int latmenc_decode_extradata(LATMContext *ctx, uint8_t *buf, int size) return AVERROR_INVALIDDATA; } /* FIXME: are any formats not allowed in LATM? */ + if (m4ac.object_type > AOT_SBR && m4ac.object_type != AOT_ALS) { latmenc_err("Muxing MPEG-4 AOT %d in LATM is not supported\n", m4ac.object_type); @@ -63,14 +67,17 @@ int latmenc_decode_extradata(LATMContext *ctx, uint8_t *buf, int size) } ctx->channel_conf = m4ac.chan_config; ctx->object_type = m4ac.object_type; + return 0; } static void latmenc_write_frame_header(LATMContext *ctx, uint8_t *extradata, int extradata_size, PutBitContext *bs) { int header_size; + /* AudioMuxElement */ put_bits(bs, 1, !!ctx->counter); + if (!ctx->counter) { /* StreamMuxConfig */ @@ -79,6 +86,7 @@ static void latmenc_write_frame_header(LATMContext *ctx, uint8_t *extradata, int put_bits(bs, 6, 0); /* numSubFrames */ put_bits(bs, 4, 0); /* numProgram */ put_bits(bs, 3, 0); /* numLayer */ + /* AudioSpecificConfig */ if (ctx->object_type == AOT_ALS) { @@ -90,6 +98,7 @@ static void latmenc_write_frame_header(LATMContext *ctx, uint8_t *extradata, int // + 3 assumes not scalable and dependsOnCoreCoder == 0, // see decode_ga_specific_config in libavcodec/aacdec.c avpriv_copy_bits(bs, extradata, ctx->off + 3); + if (!ctx->channel_conf) { GetBitContext gb; @@ -99,11 +108,14 @@ static void latmenc_write_frame_header(LATMContext *ctx, uint8_t *extradata, int avpriv_copy_pce_data(bs, &gb); } } + put_bits(bs, 3, 0); /* frameLengthType */ put_bits(bs, 8, 0xff); /* latmBufferFullness */ + put_bits(bs, 1, 0); /* otherDataPresent */ put_bits(bs, 1, 0); /* crcCheckPresent */ } + ctx->counter++; ctx->counter %= ctx->mod; } @@ -112,15 +124,22 @@ int latmenc_write_packet(LATMContext *ctx, uint8_t *data, int size, uint8_t *ext { PutBitContext bs; int i, len; + if (size > 0x1fff) goto too_large; + init_put_bits(&bs, ctx->buffer, size + 1024 + MAX_EXTRADATA_SIZE); + latmenc_write_frame_header(ctx, extradata, extradata_size, &bs); + /* PayloadLengthInfo() */ for (i = 0; i <= size - 255; i += 255) put_bits(&bs, 8, 255); + put_bits(&bs, 8, size - i); + /* The LATM payload is written unaligned */ + /* PayloadMux() */ if (size && (data[0] & 0xe1) == 0x81) { @@ -137,17 +156,23 @@ int latmenc_write_packet(LATMContext *ctx, uint8_t *data, int size, uint8_t *ext } else avpriv_copy_bits(&bs, data, 8 * size); + avpriv_align_put_bits(&bs); flush_put_bits(&bs); + len = put_bits_count(&bs) >> 3; + if (len > 0x1fff) goto too_large; + memcpy(ctx->loas_header, "\x56\xe0\x00", 3); ctx->loas_header[1] |= (len >> 8) & 0x1f; ctx->loas_header[2] |= len & 0xff; ctx->len = len; return 0; + too_large: latmenc_err("LATM packet size larger than maximum size 0x1fff\n"); return AVERROR_INVALIDDATA; } + diff --git a/libeplayer3-arm/external/ffmpeg/src/mpeg4audio.c b/libeplayer3-arm/external/ffmpeg/src/mpeg4audio.c index f43a568..934dc18 100644 --- a/libeplayer3-arm/external/ffmpeg/src/mpeg4audio.c +++ b/libeplayer3-arm/external/ffmpeg/src/mpeg4audio.c @@ -34,16 +34,21 @@ static int parse_config_ALS(GetBitContext *gb, MPEG4AudioConfig *c) { if (get_bits_left(gb) < 112) return -1; + if (get_bits_long(gb, 32) != MKBETAG('A', 'L', 'S', '\0')) return -1; + // override AudioSpecificConfig channel configuration and sample rate // which are buggy in old ALS conformance files c->sample_rate = get_bits_long(gb, 32); + // skip number of samples skip_bits_long(gb, 32); + // read number of channels c->chan_config = 0; c->channels = get_bits(gb, 16) + 1; + return 0; } @@ -79,11 +84,14 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, { GetBitContext gb; int specific_config_bitindex, ret; + if (bit_size <= 0) return AVERROR_INVALIDDATA; + ret = init_get_bits(&gb, buf, bit_size); if (ret < 0) return ret; + c->object_type = get_object_type(&gb); c->sample_rate = get_sample_rate(&gb, &c->sampling_index); c->chan_config = get_bits(&gb, 4); @@ -110,15 +118,19 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, c->ext_sample_rate = 0; } specific_config_bitindex = get_bits_count(&gb); + if (c->object_type == AOT_ALS) { skip_bits(&gb, 5); if (show_bits_long(&gb, 24) != MKBETAG('\0', 'A', 'L', 'S')) skip_bits_long(&gb, 24); + specific_config_bitindex = get_bits_count(&gb); + if (parse_config_ALS(&gb, c)) return -1; } + if (c->ext_object_type != AOT_SBR && sync_extension) { while (get_bits_left(&gb) > 15) @@ -141,12 +153,14 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, get_bits1(&gb); // skip 1 bit } } + //PS requires SBR if (!c->sbr) c->ps = 0; //Limit implicit PS to the HE-AACv2 Profile if ((c->ps == -1 && c->object_type != AOT_AAC_LC) || c->channels & ~0x01) c->ps = 0; + return specific_config_bitindex; } @@ -163,6 +177,7 @@ int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb) { int five_bit_ch, four_bit_ch, comment_size, bits; int offset = put_bits_count(pb); + copy_bits(pb, gb, 10); //Tag, Object Type, Frequency five_bit_ch = copy_bits(pb, gb, 4); //Front five_bit_ch += copy_bits(pb, gb, 4); //Side @@ -185,5 +200,6 @@ int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb) comment_size = copy_bits(pb, gb, 8); for (; comment_size > 0; comment_size--) copy_bits(pb, gb, 8); + return put_bits_count(pb) - offset; } diff --git a/libeplayer3-arm/external/flv2mpeg4/src/bitreader.h b/libeplayer3-arm/external/flv2mpeg4/src/bitreader.h index 4b3d2c9..d375839 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/bitreader.h +++ b/libeplayer3-arm/external/flv2mpeg4/src/bitreader.h @@ -56,6 +56,7 @@ static uint32 get_u24(BR *p) uint32 a = get_u8(p); uint32 b = get_u8(p); uint32 c = get_u8(p); + return (a << 16) | (b << 8) | c; } @@ -65,6 +66,7 @@ static uint32 get_u32(BR *p) uint32 b = get_u8(p); uint32 c = get_u8(p); uint32 d = get_u8(p); + return (a << 24) | (b << 16) | (c << 8) | d; } @@ -82,10 +84,12 @@ static uint32 show_bits(BR *p, uint32 bits) { const uint8 *pp; uint32 tmp; + pp = p->buf + p->read; tmp = (pp[0] << 24) | (pp[1] << 16) | (pp[2] << 8) | (pp[3]); tmp <<= p->bitoffset; tmp >>= 32 - bits; + return tmp; } @@ -93,10 +97,12 @@ static int32 show_sbits(BR *p, uint32 bits) { const uint8 *pp; int32 tmp; + pp = p->buf + p->read; tmp = (pp[0] << 24) | (pp[1] << 16) | (pp[2] << 8) | (pp[3]); tmp <<= p->bitoffset; tmp >>= 32 - bits; + return tmp; } @@ -150,14 +156,17 @@ static int __inline get_vlc(BR *br, const VLCtab *table, int bits, int max_depth index = show_bits(br, bits); code = table[index].code; n = table[index].n; + if (max_depth > 1 && n < 0) { flash_bits(br, bits); nb_bits = -n; + index = show_bits(br, nb_bits) + code; code = table[index].code; n = table[index].n; } + flash_bits(br, n); return code; } diff --git a/libeplayer3-arm/external/flv2mpeg4/src/bitwriter.h b/libeplayer3-arm/external/flv2mpeg4/src/bitwriter.h index 3e76f36..ead9639 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/bitwriter.h +++ b/libeplayer3-arm/external/flv2mpeg4/src/bitwriter.h @@ -57,12 +57,14 @@ static void __inline init_bw(BW *p, uint8 *buf, uint32 size) static void __inline forword_bits(BW *p, uint32 bits) { p->bitoffset += bits; + if (p->bitoffset >= 32) { p->buf[p->pos++] = (p->tmp >> 24) & 0xff; p->buf[p->pos++] = (p->tmp >> 16) & 0xff; p->buf[p->pos++] = (p->tmp >> 8) & 0xff; p->buf[p->pos++] = (p->tmp >> 0) & 0xff; + p->tmp = 0; p->bitoffset -= 32; } @@ -71,6 +73,7 @@ static void __inline forword_bits(BW *p, uint32 bits) static void __inline put_bits(BW *p, uint32 bits, uint32 value) { uint32 shift = 32 - p->bitoffset - bits; + if (shift <= 32) { p->tmp |= value << shift; @@ -81,6 +84,7 @@ static void __inline put_bits(BW *p, uint32 bits, uint32 value) shift = bits - (32 - p->bitoffset); p->tmp |= value >> shift; forword_bits(p, bits - shift); + p->tmp |= value << (32 - shift); forword_bits(p, shift); } @@ -98,6 +102,7 @@ static void __inline pad_to_boundary(BW *p) static void __inline flash_bw(BW *p) { pad_to_boundary(p); + switch (p->bitoffset) { case 0: // nothing to do @@ -118,6 +123,7 @@ static void __inline flash_bw(BW *p) // fprintf(stderr, "flash_bw error!(%d)\n", p->bitoffset); break; } + p->tmp = 0; p->bitoffset = 0; } @@ -136,6 +142,7 @@ static void __inline put_vlcdec(BW *bw, VLCDEC *vlcdec) static void __inline m4v_stuffing(BW *p) { int length; + put_bits(p, 1, 0); length = (- p->bitoffset) & 7; if (length) put_bits(p, length, (1 << length) - 1); diff --git a/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.c b/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.c index 90e350f..dfe2261 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.c +++ b/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.c @@ -25,6 +25,7 @@ #include "dcprediction.h" + // M4V ADDED static const uint8 mpeg4_y_dc_scale_table[32] = { @@ -43,10 +44,12 @@ static int __inline get_pred(int *dc_cur, int stride, int scale) { /* B C A X */ + int A = dc_cur[-1]; int B = dc_cur[-1 - stride]; int C = dc_cur[-stride]; int pred; + if (abs(A - B) < abs(B - C)) { pred = C; @@ -55,6 +58,7 @@ static int __inline get_pred(int *dc_cur, int stride, int scale) { pred = A; } + return (pred + (scale >> 1)) / scale; } @@ -68,6 +72,7 @@ static void __inline set_dc_to_dc_cur(int *dc_cur, int level, int scale) else level = 2047; } + dc_cur[0] = level; } @@ -118,6 +123,7 @@ int dcpred_for_enc(M4V_DCPRED *p, int n, int level) int *dc_cur = p->dc_cur[n]; int scale = get_scale(p, n); int pred = get_pred(dc_cur, p->stride[n], scale); + set_dc_to_dc_cur(dc_cur, level, scale); return level - pred; } @@ -127,6 +133,7 @@ int dcpred_for_dec(M4V_DCPRED *p, int n, int level) int *dc_cur = p->dc_cur[n]; int scale = get_scale(p, n); int pred = get_pred(dc_cur, p->stride[n], scale); + level += pred; set_dc_to_dc_cur(dc_cur, level, scale); return level; @@ -137,6 +144,7 @@ static void init_plane(M4V_DCPRED *pred, int n) { int x, len = pred->stride[n] * pred->height[n]; int *p = pred->_dc[n]; + for (x = 0; x < len; x++) { p[x] = 1024; @@ -156,16 +164,20 @@ void alloc_dcpred(M4V_DCPRED *pred, int mb_width, int mb_height) const int h2 = mb_height * 2 + 1; const int w = mb_width + 1; const int h = mb_height + 1; + pred->_dc[0] = pred->_dc[1] = pred->_dc[2] = pred->_dc[3] = (int *)malloc(sizeof(int) * w2 * h2); pred->_dc[4] = (int *)malloc(sizeof(int) * w * h); pred->_dc[5] = (int *)malloc(sizeof(int) * w * h); + pred->dc[0] = pred->dc[1] = pred->dc[2] = pred->dc[3] = pred->_dc[0] + w2 + 1; pred->dc[4] = pred->_dc[4] + w + 1; pred->dc[5] = pred->_dc[5] + w + 1; + pred->stride[0] = pred->stride[1] = pred->stride[2] = pred->stride[3] = w2; pred->height[0] = pred->height[1] = pred->height[2] = pred->height[3] = h2; pred->stride[4] = pred->stride[5] = w; pred->height[4] = pred->height[5] = h; + pred->block_offset[0] = 0; pred->block_offset[1] = 1; pred->block_offset[2] = w2; diff --git a/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.h b/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.h index 456a685..936b741 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.h +++ b/libeplayer3-arm/external/flv2mpeg4/src/dcprediction.h @@ -40,6 +40,7 @@ typedef struct _M4V_DCPRED int y_dc_scale; int c_dc_scale; + } M4V_DCPRED; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libeplayer3-arm/external/flv2mpeg4/src/flv.h b/libeplayer3-arm/external/flv2mpeg4/src/flv.h index 22874b3..e2f08ce 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/flv.h +++ b/libeplayer3-arm/external/flv2mpeg4/src/flv.h @@ -65,6 +65,7 @@ typedef struct _PICTURE int width; int height; + #define FLV_I_TYPE 0 #define FLV_P_TYPE 1 @@ -156,4 +157,5 @@ static const int8 rl_inter_run[102] = static const int rl_inter_n = 102; static const int rl_inter_last = 58; + #endif // FLV_H diff --git a/libeplayer3-arm/external/flv2mpeg4/src/flv2mpeg4.c b/libeplayer3-arm/external/flv2mpeg4/src/flv2mpeg4.c index 3e22d98..36049dd 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/flv2mpeg4.c +++ b/libeplayer3-arm/external/flv2mpeg4/src/flv2mpeg4.c @@ -41,6 +41,7 @@ typedef struct _CONVCTX M4V_VOL vol; } CONVCTX; + typedef struct { uint8 *out_buf; @@ -64,6 +65,7 @@ static const uint8 ff_mpeg4_c_dc_scale_table[32] = 0, 8, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }; + static void copy_vol(PICTURE *flv_pic, M4V_VOL *vol) { vol->width = flv_pic->width; @@ -74,9 +76,11 @@ static void copy_vol(PICTURE *flv_pic, M4V_VOL *vol) static void copy_vop(PICTURE *flv_pic, M4V_VOP *vop, CONVCTX *c) { vop->qscale = flv_pic->qscale; + vop->time = c->frame % 30; vop->icount = (c->icounter + 29) / 30; vop->intra_dc_threshold = 99; + if (flv_pic->picture_type == FLV_I_TYPE) { vop->picture_type = M4V_I_TYPE; @@ -91,13 +95,16 @@ static void copy_vop(PICTURE *flv_pic, M4V_VOP *vop, CONVCTX *c) static void copy_microblock(MICROBLOCK *flv_mb, M4V_MICROBLOCK *m4v_mb) { int i; + m4v_mb->dquant = flv_mb->dquant; memcpy(m4v_mb->block, flv_mb->block, sizeof(m4v_mb->block)); // !!!!!!! m4v_mb->intra = flv_mb->intra; m4v_mb->skip = flv_mb->skip; m4v_mb->mv_type = flv_mb->mv_type; + memcpy(m4v_mb->mv_x, flv_mb->mv_x, sizeof(m4v_mb->mv_x)); // !!!!!! memcpy(m4v_mb->mv_y, flv_mb->mv_y, sizeof(m4v_mb->mv_y)); // !!!!!! + // dc rescale if (m4v_mb->intra) { @@ -106,6 +113,7 @@ static void copy_microblock(MICROBLOCK *flv_mb, M4V_MICROBLOCK *m4v_mb) m4v_mb->block[i].block[0] *= 8; m4v_mb->block[i].block[0] /= ff_mpeg4_y_dc_scale_table[m4v_mb->qscale]; } + for (i = 4; i < 6; i++) { m4v_mb->block[i].block[0] *= 8; @@ -126,7 +134,9 @@ static int write_pad_not_coded_frames(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BW *bw vop.icount = (c->icounter + 29) / 30; m4v_encode_vop_header(bw, &vop, VOL_TIME_BITS, 1); m4v_stuffing(bw); + flash_bw(bw); + // write frame if (pub_ctx->write_packet_cb(pub_ctx->usr_data, 0, @@ -136,10 +146,13 @@ static int write_pad_not_coded_frames(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BW *bw { return -1; } + clear_bw(bw); + c->frame++; c->icounter++; } + return 0; } @@ -151,9 +164,12 @@ static int write_m4v_picture_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, B int x, y; int mb_width = (flvpic->width + 15) / 16; int mb_height = (flvpic->height + 15) / 16; + memset(&vop, 0, sizeof(vop)); + copy_vop(flvpic, &vop, c); m4v_encode_vop_header(bw, &vop, VOL_TIME_BITS, 0); + // transcode flv to mpeg4 for (y = 0; y < mb_height; y++) { @@ -161,6 +177,7 @@ static int write_m4v_picture_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, B { memset(&mb, 0, sizeof(mb)); memset(&m4v_mb, 0, sizeof(m4v_mb)); + if (vop.picture_type == M4V_I_TYPE) { mb.intra = 1; @@ -180,8 +197,10 @@ static int write_m4v_picture_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, B } } } + m4v_stuffing(bw); flash_bw(bw); + // write frame if (pub_ctx->write_packet_cb(pub_ctx->usr_data, vop.picture_type == M4V_I_TYPE, @@ -191,19 +210,25 @@ static int write_m4v_picture_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, B { return -1; } + c->frame++; c->icounter++; + return 0; } static int write_m4v_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, BW *bw, uint32 time) { PICTURE picture; + memset(&picture, 0, sizeof(picture)); init_dcpred(&c->vol.dcpred); + if (decode_picture_header(br, &picture) < 0) return -1; if (c->width != picture.width || c->height != picture.height) return -1; //size changed.. + copy_vol(&picture, &c->vol); + if (picture.picture_type == FLV_I_TYPE) { c->icounter = 0; @@ -212,10 +237,12 @@ static int write_m4v_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, BW *bw, u { if (write_pad_not_coded_frames(pub_ctx, c, bw, time) < 0) return -1; } + if (write_m4v_picture_frame(pub_ctx, c, br, bw, &picture, time) < 0) { return -1; } + return 0; } @@ -235,16 +262,23 @@ int flv2mpeg4_prepare_extra_data(flv2mpeg4_CTX *ctx) CTX *p = ctx->priv; BW bw; CONVCTX *c = &(p->conv); + M4V_VOP vop; memset(&vop, 0, sizeof(vop)); + init_bw(&bw, p->out_buf, PACKETBUFFER_SIZE); + c->vol.width = c->width; c->vol.height = c->height; c->vol.time_bits = VOL_TIME_BITS; // 0-31 + m4v_encode_m4v_header(&bw, &c->vol, 0); + m4v_stuffing(&bw); flash_bw(&bw); + alloc_dcpred(&c->vol.dcpred, (c->width + 15) / 16, (c->height + 15) / 16); + return ctx->write_extradata_cb(ctx->usr_data, c->width, c->height, 200 * 1000, bw.buf, bw.pos); } @@ -265,20 +299,26 @@ flv2mpeg4_CTX *flv2mpeg4_init_ctx(void *priv_data, int width, int height, flv2mp pub_ctx->priv = malloc(sizeof(CTX)); memset(pub_ctx->priv, 0x0, sizeof(CTX)); CTX *ctx = pub_ctx->priv; + ctx->conv.width = width; ctx->conv.height = height; ctx->out_buf = malloc(PACKETBUFFER_SIZE); memset(ctx->out_buf, 0x0, PACKETBUFFER_SIZE); memset(&(ctx->vol), 0x0, sizeof(ctx->vol)); + return pub_ctx; } void flv2mpeg4_release_ctx(flv2mpeg4_CTX **pub_ctx) { CTX *ctx = (*pub_ctx)->priv; + free_dcpred(&ctx->conv.vol.dcpred); free(ctx->out_buf); free(ctx); free(*pub_ctx); *pub_ctx = NULL; } + + + diff --git a/libeplayer3-arm/external/flv2mpeg4/src/flvdecoder.c b/libeplayer3-arm/external/flv2mpeg4/src/flvdecoder.c index edfba70..9d84a31 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/flvdecoder.c +++ b/libeplayer3-arm/external/flv2mpeg4/src/flvdecoder.c @@ -38,6 +38,7 @@ static const uint8 zig_zag_scan[64] = 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; + static const VLCtab vlc_table_intra_MCBPC[] = //: table_size=72 table_allocated=128 bits=6 { {64, -3}, @@ -127,6 +128,7 @@ static const VLCtab vlc_table_rl_inter[] = //: table_size=554 table_allocated=10 {100, 3}, {101, 3}, {8, 1}, {7, 1} }; + static const VLCtab vlc_table_mv[] = //mv_vlc: table_size=538 table_allocated=1024 bits=9 { {512, -3}, {520, -2}, {524, -1}, {526, -1}, {528, -1}, {530, -1}, {532, -1}, {534, -1}, {536, -1}, {10, 9}, @@ -181,6 +183,7 @@ static int __inline decode_DC(BR *p) return -1; } if (level == 255) level = 128; + // printf("DC: %d\n", level); return level; } @@ -188,6 +191,7 @@ static int __inline decode_DC(BR *p) static int __inline decode_AC(BR *p, BLOCK *block, int escape_type, int i) { int code, run, level, last, sign; + while (1) { code = get_vlc(p, vlc_table_rl_inter, 9, 2); @@ -196,12 +200,14 @@ static int __inline decode_AC(BR *p, BLOCK *block, int escape_type, int i) printf("invalid Huffman code in getblock()\n"); return -1; } + if (code == rl_inter_n) { //escape if (escape_type == 1) { int is11bit = get_bits(p, 1); + last = get_bits(p, 1); run = get_bits(p, 6); if (is11bit) @@ -227,9 +233,11 @@ static int __inline decode_AC(BR *p, BLOCK *block, int escape_type, int i) run = rl_inter_run[code]; level = rl_inter_level[code]; last = code >= rl_inter_last; + sign = get_bits(p, 1); if (sign) level = -level; } + i += run; if (i >= 64) { @@ -240,6 +248,7 @@ static int __inline decode_AC(BR *p, BLOCK *block, int escape_type, int i) if (last) break; i++; } + block->last_index = i; return 0; } @@ -252,12 +261,15 @@ static int __inline decode_intra_block(BR *p, BLOCK *block, int escape_type, int printf("dc error.\n"); return -1; } + block->block[0] = level; block->last_index = 0; + if (!coded) { return 0; } + if (decode_AC(p, block, escape_type, 1) < 0) return -1; return 0; } @@ -265,10 +277,12 @@ static int __inline decode_intra_block(BR *p, BLOCK *block, int escape_type, int static int __inline decode_inter_block(BR *p, BLOCK *block, int escape_type, int coded) { block->last_index = -1; + if (!coded) { return 0; } + if (decode_AC(p, block, escape_type, 0) < 0) return -1; return 0; } @@ -298,6 +312,7 @@ static int __inline get_inter_MCBPC(BR *br) if (cbpc < 0) return -1; } while (cbpc == 20); + return cbpc; } @@ -316,11 +331,14 @@ static int __inline decode_motion(BR *br, VLCDEC *vlcdec) { int tmp; int code = get_vlcdec(br, vlc_table_mv, 9, 2, vlcdec); + vlcdec->bits_ex = 0; + if (code == 0) return 0; if (code < 0) return -1; + tmp = get_bits(br, 1); /* vlcdec->value |= (tmp << vlcdec->bits); @@ -331,6 +349,7 @@ static int __inline decode_motion(BR *br, VLCDEC *vlcdec) */ vlcdec->bits_ex = 1; vlcdec->value_ex = tmp; + return 0; } @@ -338,23 +357,28 @@ static int __inline decode_intra_mb_internal(BR *p, MICROBLOCK *mb, int escape_t { int cbpy, cbp; int i; + cbpy = get_cbpy(p); if (cbpy < 0) { printf("cbpy error\n"); return -1; } + cbp = (cbpc & 3) | (cbpy << 2); + if (dquant) { mb->dquant = decode_dquant(p); qscale += mb->dquant; } + for (i = 0; i < 6; i++) { if (decode_intra_block(p, &mb->block[i], escape_type, cbp & 32) != 0) return -1; cbp += cbp; } + return 0; } @@ -362,19 +386,23 @@ static int __inline decode_inter_mb_internal(BR *p, MICROBLOCK *mb, int escape_t { int cbpy, cbp; int i; + cbpy = get_cbpy(p); if (cbpy < 0) { printf("cbpy error\n"); return -1; } + cbpy ^= 0xF; cbp = (cbpc & 3) | (cbpy << 2); + if (dquant) { mb->dquant = decode_dquant(p); qscale += mb->dquant; } + if ((cbpc & 16) == 0) { // 16x16 motion prediction @@ -392,11 +420,13 @@ static int __inline decode_inter_mb_internal(BR *p, MICROBLOCK *mb, int escape_t } mb->mv_type = MV_TYPE_8X8; } + for (i = 0; i < 6; i++) { if (decode_inter_block(p, &mb->block[i], escape_type, cbp & 32) != 0) return -1; cbp += cbp; } + return 0; } @@ -410,18 +440,22 @@ int decode_I_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale) printf("intra_MCBPC error\n"); return -1; } + dquant = cbpc & 4; decode_intra_mb_internal(p, mb, escape_type, qscale, cbpc, dquant); + if (show_bits(p, 16) == 0) { // printf("slice end???\n"); } + return 0; } int decode_P_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale) { int cbpc = get_inter_MCBPC(p); + if (cbpc == -1) { printf("inter_MCBPC error\n"); @@ -435,6 +469,7 @@ int decode_P_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale) { int dquant = cbpc & 8; mb->skip = 0; + if ((cbpc & 4) != 0) { mb->intra = 1; @@ -446,31 +481,38 @@ int decode_P_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale) decode_inter_mb_internal(p, mb, escape_type, qscale, cbpc, dquant); } } + if (show_bits(p, 16) == 0) { // printf("slice end???\n"); } + return 0; } int decode_picture_header(BR *p, PICTURE *picture) { int tmp, width = 0, height = 0; + if (get_bits(p, 17) != 1) { fprintf(stderr, "start code error\n"); return -1; } + tmp = get_bits(p, 5); if (tmp != 0 && tmp != 1) { fprintf(stderr, "picture format error\n"); return -1; } + picture->escape_type = tmp; picture->frame_number = get_bits(p, 8); + // printf("picture_format: %d\n", tmp); // printf("picture_number: %d\n", get_bits(p, 8)); + tmp = get_bits(p, 3); switch (tmp) { @@ -501,21 +543,27 @@ int decode_picture_header(BR *p, PICTURE *picture) fprintf(stderr, "size error\n"); return -1; } + picture->width = width; picture->height = height; // printf("width: %d height: %d\n", width, height); + picture->picture_type = get_bits(p, 2); // printf("picture_type: %d\n", tmp); + tmp = get_bits(p, 1); // printf("deblocking flag: %d\n", tmp); + tmp = get_bits(p, 5); picture->qscale = tmp; // printf("qscale: %d\n", tmp); + // PEI while (get_bits(p, 1) != 0) { flash_bits(p, 8); } + // dump_marker(0, "dd header end"); return 0; } diff --git a/libeplayer3-arm/external/flv2mpeg4/src/m4v.h b/libeplayer3-arm/external/flv2mpeg4/src/m4v.h index eddb7dd..df5fd2e 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/m4v.h +++ b/libeplayer3-arm/external/flv2mpeg4/src/m4v.h @@ -134,4 +134,6 @@ static const uint8 alternate_vertical_scan[64] = 38, 46, 54, 62, 39, 47, 55, 63, }; + #endif // M4V_H + diff --git a/libeplayer3-arm/external/flv2mpeg4/src/m4vencode.c b/libeplayer3-arm/external/flv2mpeg4/src/m4vencode.c index 7860d83..139a91b 100644 --- a/libeplayer3-arm/external/flv2mpeg4/src/m4vencode.c +++ b/libeplayer3-arm/external/flv2mpeg4/src/m4vencode.c @@ -63,6 +63,7 @@ static const uint32 vlce_inter_MCBPC_bits[28] = static void __inline encode_DC(BW *p, int level, int n) { if (level < -255 || level > 255) printf("dc overflow\n"); + #if 1 level += 256; if (n < 4) @@ -74,6 +75,7 @@ static void __inline encode_DC(BW *p, int level, int n) put_bits(p, uni_DCtab_chrom_len[level], uni_DCtab_chrom_bits[level]); } #else + int size, v; /* find number of bits */ size = 0; @@ -83,6 +85,7 @@ static void __inline encode_DC(BW *p, int level, int n) v >>= 1; size++; } + if (n < 4) { /* luminance */ @@ -93,6 +96,7 @@ static void __inline encode_DC(BW *p, int level, int n) /* chrominance */ put_bits(p, DCtab_chrom[size][1], DCtab_chrom[size][0]); } + /* encode remaining bits */ if (size > 0) { @@ -102,7 +106,9 @@ static void __inline encode_DC(BW *p, int level, int n) if (size > 8) put_bits(p, 1, 1); } + #endif + } static void __inline encode_escape_3(BW *p, int last, int run, int level) @@ -129,10 +135,13 @@ static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra) int i = intra; int last_index = block->last_index; int last_non_zero = i - 1; + const uint8 *scan_table = zig_zag_scan; // !!! + #if 1 const uint8 *len_tab; const uint32 *bits_tab; + if (intra) { len_tab = uni_mpeg4_intra_rl_len; @@ -143,6 +152,7 @@ static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra) len_tab = uni_mpeg4_inter_rl_len; bits_tab = uni_mpeg4_inter_rl_bits; } + for (; i < last_index; i++) { int level = block->block[scan_table[i]]; @@ -159,9 +169,11 @@ static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra) { encode_escape_3(p, 0, run, level); } + last_non_zero = i; } } + { int level = block->block[scan_table[i]]; int run = i - last_non_zero - 1; @@ -179,6 +191,7 @@ static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra) #else const RL *rl; int last, sign, code; + if (intra) { rl = &rl_intra; @@ -187,6 +200,7 @@ static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra) { rl = &rl_inter; } + for (; i <= last_index; i++) { const int slevel = block->block[scan_table[i]]; @@ -202,6 +216,7 @@ static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra) sign = 1; level = -level; } + code = get_rl_index(rl, last, run, level); put_bits(p, rl->table_vlc[code][1], rl->table_vlc[code][0]); if (code == rl->n) @@ -210,6 +225,7 @@ static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra) level1 = level - rl->max_level[run][last]; if (level1 < 1) goto esc2; + code = get_rl_index(rl, last, run, level1); if (code == rl->n) { @@ -255,7 +271,10 @@ esc3: last_non_zero = i; } } + #endif + + } static void __inline encode_intra_block(BW *bw, M4V_BLOCK *block, int n) @@ -293,6 +312,7 @@ static void __inline encode_inter_8x8_MCBPC(BW *bw, int cbpc) put_bits(bw, vlce_inter_MCBPC_bits[cbpc + 16], vlce_inter_MCBPC_code[cbpc + 16]); } + // same as H.263 static void __inline encode_cbpy(BW *bw, int cbpy) { @@ -320,6 +340,7 @@ static void __inline encode_motion(BW *bw, VLCDEC *mv_x, VLCDEC *mv_y) { put_bits(bw, mv_x->bits_ex - 1, mv_x->value_ex >> 1); } + } put_vlcdec(bw, mv_y); if (mv_y->bits_ex) @@ -337,6 +358,7 @@ static void __inline encode_mb_inter_internal(BW *bw, M4V_MICROBLOCK *mb) { int cbp = 0, cbpc, cbpy; int i; + for (i = 0; i < 6; i++) { if (mb->block[i].last_index >= 0) @@ -344,10 +366,13 @@ static void __inline encode_mb_inter_internal(BW *bw, M4V_MICROBLOCK *mb) cbp |= 1 << (5 - i); } } + cbpc = cbp & 3; cbpy = cbp >> 2; cbpy ^= 0xF; + if (mb->dquant) cbpc += 8; + switch (mb->mv_type) { case MV_TYPE_16X16: @@ -366,6 +391,7 @@ static void __inline encode_mb_inter_internal(BW *bw, M4V_MICROBLOCK *mb) } break; } + for (i = 0; i < 6; i++) { encode_inter_block(bw, &mb->block[i]); @@ -376,6 +402,7 @@ static void __inline encode_mb_intra_internal(BW *bw, M4V_MICROBLOCK *mb, int if { int cbp = 0, cbpc, cbpy; int i; + for (i = 0; i < 6; i++) { if (mb->block[i].last_index >= 1) @@ -383,6 +410,7 @@ static void __inline encode_mb_intra_internal(BW *bw, M4V_MICROBLOCK *mb, int if cbp |= 1 << (5 - i); } } + cbpc = cbp & 3; if (iframe) { @@ -394,10 +422,15 @@ static void __inline encode_mb_intra_internal(BW *bw, M4V_MICROBLOCK *mb, int if if (mb->dquant) cbpc += 8; encode_intra_P_MCBPC(bw, cbpc); } + put_bits(bw, 1, 0); // AC Prediction = no + cbpy = cbp >> 2; + encode_cbpy(bw, cbpy); encode_dquant(bw, mb->dquant); + + for (i = 0; i < 6; i++) { encode_intra_block(bw, &mb->block[i], i); @@ -409,15 +442,20 @@ static int __inline encode_vo_header(BW *p) { put_bits(p, 16, 0); put_bits(p, 16, VOS_STARTCODE); + put_bits(p, 8, 1); // *** profile_and_level_indidation + put_bits(p, 16, 0); put_bits(p, 16, VISUAL_OBJECT_STARTCODE); + put_bits(p, 1, 1); put_bits(p, 4, 1); // vo_vel_id put_bits(p, 3, 1); // priority put_bits(p, 4, 1); // visual_object_type = video object put_bits(p, 1, 0); // video signal type = no clue + m4v_stuffing(p); + return 0; } @@ -425,19 +463,28 @@ static int __inline encode_vol_header(BW *p, M4V_VOL *vol) { const int vo_number = 0; const int vol_number = 0; + put_bits(p, 16, 0); put_bits(p, 16, 0x100 + vo_number); + put_bits(p, 16, 0); put_bits(p, 16, 0x120 + vol_number); + put_bits(p, 1, 0); // random_accessible_vol put_bits(p, 8, 1); // video_object_type_indication = Simple Object Type + put_bits(p, 1, 0); //is_object_layer_identifier + put_bits(p, 4, 1); // *** aspect_ratio_info = 1(1:1) + put_bits(p, 1, 0); //vol_control_parameters + put_bits(p, 2, 0); // shape_type put_bits(p, 1, 1); // marker + if (vol->time_bits != 5) return -1; // for vop_time_increment_resolution = 30 put_bits(p, 16, 30); // *** vop_time_increment_resolution = 30 + put_bits(p, 1, 1); // marker put_bits(p, 1, 0); // fixed vop rate = no put_bits(p, 1, 1); // marker @@ -450,10 +497,12 @@ static int __inline encode_vol_header(BW *p, M4V_VOL *vol) put_bits(p, 1, 0); // sprite = disable put_bits(p, 1, 0); // not8bit = false put_bits(p, 1, 0); // quant type = H.263 + put_bits(p, 1, 1); // complexity estimaition disable = true put_bits(p, 1, 1); // resync marker disable = true put_bits(p, 1, 0); // data pertitioning = false put_bits(p, 1, 0); // scalability = false + m4v_stuffing(p); return 0; } @@ -461,14 +510,21 @@ static int __inline encode_vol_header(BW *p, M4V_VOL *vol) static int __inline encode_vop_header(BW *p, M4V_VOP *vop, int time_bits, int vop_not_coded) { // static int time_old = 0; + int time_incr = vop->icount; if (vop->time != 0) time_incr = 0; + put_bits(p, 16, 0); put_bits(p, 16, VOP_STARTCODE); + put_bits(p, 2, vop->picture_type); + + // printf("not_code:%d vop_time: %d\n", vop_not_coded, vop->time); + // printf("pic:%d icount:%d vop_time: %d\n", vop->picture_type, time_incr, vop->time); + /* if (time_old > vop->time) { put_bits(p, 1, 1); @@ -476,54 +532,70 @@ static int __inline encode_vop_header(BW *p, M4V_VOP *vop, int time_bits, int vo time_old = vop->time; */ + // !!!!! while (time_incr--) put_bits(p, 1, 1); put_bits(p, 1, 0); + put_bits(p, 1, 1); // marker put_bits(p, time_bits, vop->time); // time_increment put_bits(p, 1, 1); // marker + if (vop_not_coded) { put_bits(p, 1, 0); // vop coded return 0; } + put_bits(p, 1, 1); // vop coded + if (vop->picture_type == M4V_P_TYPE) { put_bits(p, 1, vop->rounding_type); // rounding type } + put_bits(p, 3, 0); // intra dc VLC threashold + put_bits(p, 5, vop->qscale); // qscale + if (vop->picture_type != M4V_I_TYPE) { put_bits(p, 3, vop->f_code); } + if (vop->picture_type == M4V_B_TYPE) { put_bits(p, 3, vop->b_code); } + return 0; } static __inline int encode_gop_header(BW *bw, uint32 time_ms) { int sec, min, hour; + sec = time_ms / 1000; min = sec / 60; sec %= 60; hour = min / 60; min %= 60; hour %= 24; + put_bits(bw, 16, 0); put_bits(bw, 16, GOP_STARTCODE); + put_bits(bw, 5, hour); put_bits(bw, 6, min); put_bits(bw, 1, 1); put_bits(bw, 6, sec); + put_bits(bw, 1, 0); // closed_gop == NO put_bits(bw, 1, 0); // broken link == NO + printf("GOP %02d:%02d:%02d\n", hour, min, sec); + m4v_stuffing(bw); return 0; } @@ -532,6 +604,7 @@ static int __inline encode_user_header(BW *p) { put_bits(p, 16, 0); put_bits(p, 16, USERDATA_STARTCODE); + put_bits(p, 8, 'v'); put_bits(p, 8, 'i'); put_bits(p, 8, 'x'); @@ -540,6 +613,7 @@ static int __inline encode_user_header(BW *p) put_bits(p, 8, 'n'); put_bits(p, 8, 'e'); put_bits(p, 8, 't'); + m4v_stuffing(p); return 0; } @@ -575,6 +649,7 @@ void m4v_encode_P_mb(BW *bw, M4V_MICROBLOCK *mb) { put_bits(bw, 1, 0); // coded } + if (mb->intra) { encode_mb_intra_internal(bw, mb, 0); @@ -592,6 +667,7 @@ int m4v_encode_I_dcpred(M4V_MICROBLOCK *mb, M4V_DCPRED *dcpred, int mb_x, int mb { dcpred_set_qscale(dcpred, mb->qscale); dcpred_set_pos(dcpred, mb_x, mb_y); + for (n = 0; n < 6; n ++) { int level = dcpred_for_enc(dcpred, n, mb->block[n].block[0]); diff --git a/libeplayer3-arm/include/aac.h b/libeplayer3-arm/include/aac.h index 4455043..33f32fd 100644 --- a/libeplayer3-arm/include/aac.h +++ b/libeplayer3-arm/include/aac.h @@ -29,6 +29,7 @@ static inline int HasADTSHeader(uint8_t *data, int size) { return 1; } + return 0; } diff --git a/libeplayer3-arm/include/bcm_ioctls.h b/libeplayer3-arm/include/bcm_ioctls.h index ef118e5..d52f298 100644 --- a/libeplayer3-arm/include/bcm_ioctls.h +++ b/libeplayer3-arm/include/bcm_ioctls.h @@ -35,6 +35,7 @@ typedef enum CT_VP9 } video_codec_type_t; + typedef enum { STREAMTYPE_UNKNOWN = -1, @@ -56,6 +57,8 @@ typedef enum STREAMTYPE_SPARK = 21, } video_stream_type_t; + + typedef enum { AUDIOTYPE_UNKNOWN = -1, @@ -75,4 +78,8 @@ typedef enum AUDIOTYPE_RAW = 0xf } audio_stream_type_t; + + + #endif /* H_DVB_BCM_H */ + diff --git a/libeplayer3-arm/include/debug.h b/libeplayer3-arm/include/debug.h index 9149895..1740868 100644 --- a/libeplayer3-arm/include/debug.h +++ b/libeplayer3-arm/include/debug.h @@ -6,6 +6,7 @@ static inline void Hexdump(unsigned char *Data, int length) { + int k; for (k = 0; k < length; k++) { @@ -14,6 +15,7 @@ static inline void Hexdump(unsigned char *Data, int length) printf("\n"); } printf("\n"); + } #endif diff --git a/libeplayer3-arm/include/manager.h b/libeplayer3-arm/include/manager.h index 81515bc..baed788 100644 --- a/libeplayer3-arm/include/manager.h +++ b/libeplayer3-arm/include/manager.h @@ -94,6 +94,7 @@ typedef struct TrackDescription_s int32_t aspect_ratio_num; int32_t aspect_ratio_den; int progressive; + } TrackDescription_t; struct Context_s; @@ -104,6 +105,7 @@ typedef struct Manager_s char *Name; int (* Command)(Context_t *, ManagerCmd_t, void *); char **Capabilities; + } Manager_t; typedef struct ManagerHandler_s diff --git a/libeplayer3-arm/include/misc.h b/libeplayer3-arm/include/misc.h index 4934180..f1114b4 100644 --- a/libeplayer3-arm/include/misc.h +++ b/libeplayer3-arm/include/misc.h @@ -56,14 +56,17 @@ static inline char *basename(char *name) { int i = 0; int pos = 0; + while (name[i] != 0) { if (name[i] == '/') pos = i; i++; } + if (name[pos] == '/') pos++; + return name + pos; } @@ -73,6 +76,7 @@ static inline char *dirname(char *name) static char path[100]; uint32_t i = 0; int32_t pos = 0; + while ((name[i] != 0) && (i < sizeof(path))) { if (name[i] == '/') @@ -82,8 +86,10 @@ static inline char *dirname(char *name) path[i] = name[i]; i++; } + path[i] = 0; path[pos] = 0; + return path; } diff --git a/libeplayer3-arm/include/output.h b/libeplayer3-arm/include/output.h index 16a61f1..533e60a 100644 --- a/libeplayer3-arm/include/output.h +++ b/libeplayer3-arm/include/output.h @@ -74,6 +74,7 @@ typedef struct Output_s int32_t (* Command)(Context_t *, OutputCmd_t, void *); int32_t (* Write)(Context_t *, void *); char **Capabilities; + } Output_t; extern Output_t LinuxDvbOutput; diff --git a/libeplayer3-arm/include/pes.h b/libeplayer3-arm/include/pes.h index 2026d4f..1b2d019 100644 --- a/libeplayer3-arm/include/pes.h +++ b/libeplayer3-arm/include/pes.h @@ -12,8 +12,10 @@ #define PES_START_CODE_RESERVED_4 0xfd #define PES_VERSION_FAKE_START_CODE 0x31 + #define MAX_PES_PACKET_SIZE (65535) + /* start codes */ #define PCM_PES_START_CODE 0xbd #define PRIVATE_STREAM_1_PES_START_CODE 0xbd diff --git a/libeplayer3-arm/include/stm_ioctls.h b/libeplayer3-arm/include/stm_ioctls.h index bdcd8dc..fcb19ee 100644 --- a/libeplayer3-arm/include/stm_ioctls.h +++ b/libeplayer3-arm/include/stm_ioctls.h @@ -92,6 +92,7 @@ typedef enum VIDEO_ENCODING_PRIVATE } video_encoding_t; + /* * List of possible audio encodings - used to select frame parser and codec. */ @@ -198,6 +199,7 @@ typedef struct dvb_play_info_s typedef dvb_play_info_t video_play_info_t; typedef dvb_play_info_t audio_play_info_t; + typedef enum { #define DVB_OPTION_VALUE_DISABLE 0 @@ -283,6 +285,7 @@ typedef enum // Legacy typo correction #define DVP_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING DVB_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING + typedef dvb_option_t video_option_t; /* Decoder commands */ @@ -293,6 +296,7 @@ typedef dvb_option_t video_option_t; #define VIDEO_CMD_SET_OPTION (4) #define VIDEO_CMD_GET_OPTION (5) + /* Flags for VIDEO_CMD_FREEZE */ #define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0) diff --git a/libeplayer3-arm/include/writer.h b/libeplayer3-arm/include/writer.h index 5f09166..b72636a 100644 --- a/libeplayer3-arm/include/writer.h +++ b/libeplayer3-arm/include/writer.h @@ -26,6 +26,8 @@ typedef struct ssize_t (* WriteV) (int, const struct iovec *, size_t); } WriterAVCallData_t; + + typedef struct WriterCaps_s { char *name; @@ -88,6 +90,6 @@ Writer_t *getDefaultVideoWriter(); Writer_t *getDefaultAudioWriter(); ssize_t write_with_retry(int fd, const void *buf, size_t size); ssize_t writev_with_retry(int fd, const struct iovec *iov, size_t ic); -ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, const void *buf, size_t size); +ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, const void *buf, size_t size); #endif diff --git a/libeplayer3-arm/main/exteplayer.c b/libeplayer3-arm/main/exteplayer.c index 54526c8..a6e0aea 100644 --- a/libeplayer3-arm/main/exteplayer.c +++ b/libeplayer3-arm/main/exteplayer.c @@ -101,34 +101,42 @@ static void *TermThreadFun(void *arg __attribute__((unused))) int cl = -1; int nfds = 1; fd_set readfds; + unlink(socket_path); if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { perror("TermThreadFun socket error"); goto finish; } + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { perror("TermThreadFun bind error"); goto finish; } + if (listen(fd, 1) == -1) { perror("TermThreadFun listen error"); goto finish; } + FD_ZERO(&readfds); FD_SET(g_pfd[0], &readfds); FD_SET(fd, &readfds); + nfds = fd > g_pfd[0] ? fd + 1 : g_pfd[0] + 1; + while (select(nfds, &readfds, NULL, NULL, NULL) == -1 && errno == EINTR) { /* Restart if interrupted by signal */ continue; } + if (FD_ISSET(fd, &readfds)) { pthread_mutex_lock(&playbackStartMtx); @@ -139,10 +147,12 @@ static void *TermThreadFun(void *arg __attribute__((unused))) kill(getpid(), SIGINT); pthread_mutex_unlock(&playbackStartMtx); } + finish: close(cl); close(fd); pthread_exit(NULL); + } static void map_inter_file_path(char *filename) @@ -170,19 +180,24 @@ static int kbhit(void) { struct timeval tv; fd_set readfds; + tv.tv_sec = 1; tv.tv_usec = 0; + FD_ZERO(&readfds); - FD_SET(0,&readfds); + FD_SET(0, &readfds); FD_SET(g_pfd[0], &readfds); - if(-1 == select(g_pfd[0] + 1, &readfds, NULL, NULL, &tv)) + + if (-1 == select(g_pfd[0] + 1, &readfds, NULL, NULL, &tv)) { return 0; } + if (FD_ISSET(0, &readfds)) { return 1; } + return 0; } @@ -194,6 +209,7 @@ static void SetBuffering() { printf("SetBuffering: failed to change the buffer of stderr\n"); } + // make fgets not blocking int flags = fcntl(stdin->_fileno, F_GETFL, 0); fcntl(stdin->_fileno, F_SETFL, flags | O_NONBLOCK); @@ -203,6 +219,7 @@ static void SetNice(int prio) { #if 0 setpriority(PRIO_PROCESS, 0, -8); + int prio = sched_get_priority_max(SCHED_RR) / 2; struct sched_param param = { @@ -221,10 +238,12 @@ static void SetNice(int prio) static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbackSwitchCmd, const char *argvBuff) { int commandRetVal = 0; + if (NULL == ptrManager || NULL == argvBuff || 2 != strnlen(argvBuff, 2)) { return -1; } + switch (argvBuff[1]) { case 'l': @@ -340,6 +359,7 @@ static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbac { ok = sscanf(argvBuff + 1, "%d", &id); } + if (id >= 0 || (1 == ok && id == -1)) { commandRetVal = g_player->playback->Command(g_player, playbackSwitchCmd, (void *)&id); @@ -349,8 +369,10 @@ static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbac break; } } + return commandRetVal; } + #if 0 static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbackSwitchCmd, const char *argvBuff) { @@ -391,6 +413,7 @@ static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbac } case 'c': { + TrackDescription_t *track = NULL; ptrManager->Command(g_player, MANAGER_GET_TRACK_DESC, &track); if (NULL != track) @@ -461,6 +484,7 @@ static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbac { ok = sscanf(argvBuff + 1, "%d", &id); } + if (id >= 0 || (1 == ok && id == -1)) { commandRetVal = g_player->playback->Command(g_player, playbackSwitchCmd, (void *)&id); @@ -470,6 +494,7 @@ static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbac break; } } + return commandRetVal; } #endif @@ -486,7 +511,7 @@ static int ParseParams(int argc, char *argv[], char *file, char *audioFile, int //int digit_optind = 0; //int aopt = 0, bopt = 0; //char *copt = 0, *dopt = 0; - while ((c = getopt(argc, argv, "we3dlsrimva:n:x:u:c:h:o:p:P:t:9:0:1:4:f:b:")) != -1) + while ((c = getopt(argc, argv, "we3dlsrimva:n:x:u:c:h:o:p:P:t:9:0:1:4:f:b:")) != -1) { switch (c) { @@ -604,9 +629,11 @@ static int ParseParams(int argc, char *argv[], char *file, char *audioFile, int ret = -1; } } + if (0 == ret && optind < argc) { ret = 0; + if (NULL == strstr(argv[optind], "://")) { strcpy(file, "file://"); @@ -629,16 +656,21 @@ int main(int argc, char *argv[]) int isTermThreadStarted = 0; char file[IPTV_MAX_FILE_PATH]; memset(file, '\0', sizeof(file)); + char audioFile[IPTV_MAX_FILE_PATH]; memset(audioFile, '\0', sizeof(audioFile)); + int audioTrackIdx = -1; int subtitleTrackIdx = -1; - uint32_t linuxDvbBufferSizeMB = 0; + + uint32_t linuxDvbBufferSizeMB = 0; + char argvBuff[256]; memset(argvBuff, '\0', sizeof(argvBuff)); int commandRetVal = -1; /* inform client that we can handle additional commands */ fprintf(stderr, "{\"EPLAYER3_EXTENDED\":{\"version\":%d}}\n", 45); + if (0 != ParseParams(argc, argv, file, audioFile, &audioTrackIdx, &subtitleTrackIdx, &linuxDvbBufferSizeMB)) { printf("Usage: exteplayer3 filePath [-u user-agent] [-c cookies] [-h headers] [-p prio] [-a] [-d] [-w] [-l] [-s] [-i] [-t audioTrackId] [-9 subtitleTrackId] [-x separateAudioUri] plabackUri\n"); @@ -671,59 +703,76 @@ int main(int argc, char *argv[]) printf("[-f ffopt=ffval] any other ffmpeg option\n"); exit(1); } + g_player = malloc(sizeof(Context_t)); if (NULL == g_player) { printf("g_player allocate error\n"); exit(1); } + pthread_mutex_init(&playbackStartMtx, NULL); do { int flags = 0; + if (pipe(g_pfd) == -1) break; + /* Make read and write ends of pipe nonblocking */ if ((flags = fcntl(g_pfd[0], F_GETFL)) == -1) break; + /* Make read end nonblocking */ flags |= O_NONBLOCK; if (fcntl(g_pfd[0], F_SETFL, flags) == -1) break; + if ((flags = fcntl(g_pfd[1], F_GETFL)) == -1) break; + /* Make write end nonblocking */ flags |= O_NONBLOCK; if (fcntl(g_pfd[1], F_SETFL, flags) == -1) break; + if (0 == pthread_create(&termThread, NULL, TermThreadFun, NULL)) isTermThreadStarted = 1; } while (0); + g_player->playback = &PlaybackHandler; g_player->output = &OutputHandler; g_player->container = &ContainerHandler; g_player->manager = &ManagerHandler; + // make sure to kill myself when parent dies prctl(PR_SET_PDEATHSIG, SIGKILL); + SetBuffering(); + //Registrating output devices g_player->output->Command(g_player, OUTPUT_ADD, "audio"); g_player->output->Command(g_player, OUTPUT_ADD, "video"); g_player->output->Command(g_player, OUTPUT_ADD, "subtitle"); - //Set LINUX DVB additional write buffer size + + //Set LINUX DVB additional write buffer size if (linuxDvbBufferSizeMB) g_player->output->Command(g_player, OUTPUT_SET_BUFFER_SIZE, &linuxDvbBufferSizeMB); + + g_player->manager->video->Command(g_player, MANAGER_REGISTER_UPDATED_TRACK_INFO, UpdateVideoTrack); if (strncmp(file, "rtmp", 4) && strncmp(file, "ffrtmp", 4)) { g_player->playback->noprobe = 1; } + PlayFiles_t playbackFiles = {file, NULL}; if ('\0' != audioFile[0]) { playbackFiles.szSecondFile = audioFile; } + commandRetVal = g_player->playback->Command(g_player, PLAYBACK_OPEN, &playbackFiles); fprintf(stderr, "{\"PLAYBACK_OPEN\":{\"OutputName\":\"%s\", \"file\":\"%s\", \"sts\":%d}}\n", g_player->output->Name, file, commandRetVal); if (commandRetVal < 0) @@ -734,17 +783,21 @@ int main(int argc, char *argv[]) } return 10; } + { pthread_mutex_lock(&playbackStartMtx); isPlaybackStarted = 1; pthread_mutex_unlock(&playbackStartMtx); + commandRetVal = g_player->output->Command(g_player, OUTPUT_OPEN, NULL); fprintf(stderr, "{\"OUTPUT_OPEN\":{\"sts\":%d}}\n", commandRetVal); commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PLAY, NULL); fprintf(stderr, "{\"PLAYBACK_PLAY\":{\"sts\":%d}}\n", commandRetVal); + if (g_player->playback->isPlaying) { PlaybackDieNowRegisterCallback(TerminateWakeUp); + HandleTracks(g_player->manager->video, (PlaybackCmd_t) - 1, "vc"); HandleTracks(g_player->manager->audio, (PlaybackCmd_t) - 1, "al"); if (audioTrackIdx >= 0) @@ -754,6 +807,7 @@ int main(int argc, char *argv[]) commandRetVal = HandleTracks(g_player->manager->audio, PLAYBACK_SWITCH_AUDIO, cmd); } HandleTracks(g_player->manager->audio, (PlaybackCmd_t) - 1, "ac"); + HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t) - 1, "sl"); if (subtitleTrackIdx >= 0) { @@ -763,6 +817,7 @@ int main(int argc, char *argv[]) } HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t) - 1, "sc"); } + while (g_player->playback->isPlaying && 0 == PlaybackDieNow(0)) { /* we made fgets non blocking */ @@ -772,10 +827,12 @@ int main(int argc, char *argv[]) kbhit(); continue; } + if (0 == argvBuff[0]) { continue; } + switch (argvBuff[0]) { case 'v': @@ -815,6 +872,7 @@ int main(int argc, char *argv[]) { int speed = 0; sscanf(argvBuff + 1, "%d", &speed); + commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SLOWMOTION, &speed); fprintf(stderr, "{\"PLAYBACK_SLOWMOTION\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal); break; @@ -833,6 +891,7 @@ int main(int argc, char *argv[]) { int speed = 0; sscanf(argvBuff + 1, "%d", &speed); + commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTFORWARD, &speed); fprintf(stderr, "{\"PLAYBACK_FASTFORWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal); break; @@ -841,6 +900,7 @@ int main(int argc, char *argv[]) { int speed = 0; sscanf(argvBuff + 1, "%d", &speed); + commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTBACKWARD, &speed); fprintf(stderr, "{\"PLAYBACK_FASTBACKWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal); break; @@ -852,11 +912,13 @@ int main(int argc, char *argv[]) int32_t lengthInt = 0; int64_t sec = 0; int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check + sscanf(argvBuff + 2, "%d", &gotoPos); if (0 <= gotoPos || force) { commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void *)&length); fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal); + lengthInt = (int32_t)length; if (10 <= lengthInt || force) { @@ -865,6 +927,7 @@ int main(int argc, char *argv[]) { sec = lengthInt - 10; } + commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SEEK_ABS, (void *)&sec); fprintf(stderr, "{\"PLAYBACK_SEEK_ABS\":{\"sec\":%lld, \"sts\":%d}}\n", sec, commandRetVal); } @@ -880,7 +943,9 @@ int main(int argc, char *argv[]) int64_t pts = 0; int32_t CurrentSec = 0; int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check + sscanf(argvBuff + 2, "%d", &seek); + commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PTS, &pts); CurrentSec = (int32_t)(pts / 90000); if (0 == commandRetVal) @@ -891,6 +956,7 @@ int main(int argc, char *argv[]) { commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void *)&length); fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal); + lengthInt = (int32_t)length; if (10 <= lengthInt || force) { @@ -959,6 +1025,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " \"isVideo\":%s, \"isAudio\":%s, \"isSubtitle\":%s, \"isDvbSubtitle\":%s, \"isTeletext\":%s, \"mayWriteToFramebuffer\":%s, \"abortRequested\":%s }}\n", \ DUMP_BOOL(ptrP->isVideo), DUMP_BOOL(ptrP->isAudio), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(ptrP->abortRequested)); } + break; } case 'n': @@ -975,24 +1042,31 @@ int main(int argc, char *argv[]) } break; } + default: { break; } } } + g_player->output->Command(g_player, OUTPUT_CLOSE, NULL); } + if (NULL != g_player) { free(g_player); } + if (isTermThreadStarted && 1 == write(g_pfd[1], "x", 1)) { pthread_join(termThread, NULL); } + pthread_mutex_destroy(&playbackStartMtx); + close(g_pfd[0]); close(g_pfd[1]); + exit(0); } diff --git a/libeplayer3-arm/manager/audio.c b/libeplayer3-arm/manager/audio.c index 6e5abde..6543f51 100644 --- a/libeplayer3-arm/manager/audio.c +++ b/libeplayer3-arm/manager/audio.c @@ -84,6 +84,7 @@ static int CurrentTrack = 0; //TRACK[0] as default. static int ManagerAdd(Context_t *context, Track_t track) { audio_mgr_printf(10, "%s::%s name=\"%s\" encoding=\"%s\" id=%d\n", __FILE__, __FUNCTION__, track.Name, track.Encoding, track.Id); + if (Tracks == NULL) { Tracks = malloc(sizeof(Track_t) * TRACKWRAP); @@ -93,11 +94,13 @@ static int ManagerAdd(Context_t *context, Track_t track) Tracks[i].Id = -1; } } + if (Tracks == NULL) { audio_mgr_err("%s:%s malloc failed\n", __FILE__, __FUNCTION__); return cERR_AUDIO_MGR_ERROR; } + int i = 0; for (i = 0; i < TRACKWRAP; i++) { @@ -107,6 +110,7 @@ static int ManagerAdd(Context_t *context, Track_t track) return cERR_AUDIO_MGR_NO_ERROR; } } + if (TrackCount < TRACKWRAP) { copyTrack(&Tracks[TrackCount], &track); @@ -117,10 +121,12 @@ static int ManagerAdd(Context_t *context, Track_t track) audio_mgr_err("%s:%s TrackCount out if range %d - %d\n", __FILE__, __FUNCTION__, TrackCount, TRACKWRAP); return cERR_AUDIO_MGR_ERROR; } + if (TrackCount > 0) { context->playback->isAudio = 1; } + audio_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); return cERR_AUDIO_MGR_NO_ERROR; } @@ -129,28 +135,36 @@ static char **ManagerList(Context_t *context __attribute__((unused))) { int i = 0, j = 0; char **tracklist = NULL; + audio_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); if (Tracks != NULL) { tracklist = malloc(sizeof(char *) * ((TrackCount * 2) + 1)); + if (tracklist == NULL) { audio_mgr_err("%s:%s malloc failed\n", __FILE__, __FUNCTION__); return NULL; } + for (i = 0, j = 0; i < TrackCount; i++, j += 2) { if (Tracks[i].pending) + { continue; + } + size_t len = strlen(Tracks[i].Name) + 20; char tmp[len]; snprintf(tmp, len, "%d %s", Tracks[i].Id, Tracks[i].Name); tracklist[j] = strdup(tmp); tracklist[j + 1] = strdup(Tracks[i].Encoding); } + tracklist[j] = NULL; } audio_mgr_printf(10, "%s::%s return %p (%d - %d)\n", __FILE__, __FUNCTION__, tracklist, j, TrackCount); + return tracklist; } @@ -159,15 +173,18 @@ static TrackDescription_t *ManagerList(Context_t *context __attribute__((unused { int i = 0; TrackDescription_t *tracklist = NULL; + audio_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); if (Tracks != NULL) { tracklist = malloc(sizeof(TrackDescription_t) * ((TrackCount) + 1)); + if (tracklist == NULL) { audio_mgr_err("%s:%s malloc failed\n", __FILE__, __FUNCTION__); return NULL; } + int j = 0; for (i = 0; i < TrackCount; ++i) { @@ -175,14 +192,17 @@ static TrackDescription_t *ManagerList(Context_t *context __attribute__((unused { continue; } + tracklist[j].Id = Tracks[i].Id; tracklist[j].Name = strdup(Tracks[i].Name); tracklist[j].Encoding = strdup(Tracks[i].Encoding); ++j; } + tracklist[j].Id = -1; } //audio_mgr_printf(10, "%s::%s return %p (%d - %d)\n", __FILE__, __FUNCTION__, tracklist, j, TrackCount); + return tracklist; } #endif @@ -190,13 +210,16 @@ static TrackDescription_t *ManagerList(Context_t *context __attribute__((unused static int ManagerDel(Context_t *context) { int i = 0; + audio_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + if (Tracks != NULL) { for (i = 0; i < TrackCount; i++) { freeTrack(&Tracks[i]); } + free(Tracks); Tracks = NULL; } @@ -205,17 +228,22 @@ static int ManagerDel(Context_t *context) audio_mgr_err("%s::%s nothing to delete!\n", __FILE__, __FUNCTION__); return cERR_AUDIO_MGR_ERROR; } + TrackCount = 0; CurrentTrack = 0; context->playback->isAudio = 0; + audio_mgr_printf(10, "%s::%s return no error\n", __FILE__, __FUNCTION__); + return cERR_AUDIO_MGR_NO_ERROR; } static int Command(Context_t *context, ManagerCmd_t command, void *argument) { int ret = cERR_AUDIO_MGR_NO_ERROR; + audio_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + switch (command) { case MANAGER_ADD: @@ -244,6 +272,7 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) case MANAGER_GET: { audio_mgr_printf(20, "%s::%s MANAGER_GET\n", __FILE__, __FUNCTION__); + if ((TrackCount > 0) && (CurrentTrack >= 0)) { *((int *)argument) = (int)Tracks[CurrentTrack].Id; @@ -277,9 +306,10 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) case MANAGER_GET_TRACK: { audio_mgr_printf(20, "%s::%s MANAGER_GET_TRACK\n", __FILE__, __FUNCTION__); + if ((TrackCount > 0) && (CurrentTrack >= 0)) { - *((Track_t **)argument) = (Track_t *) & Tracks[CurrentTrack]; + *((Track_t **)argument) = (Track_t *) &Tracks[CurrentTrack]; } else { @@ -315,6 +345,7 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) { int i; audio_mgr_printf(20, "%s::%s MANAGER_SET id=%d\n", __FILE__, __FUNCTION__, *((int *)argument)); + for (i = 0; i < TrackCount; i++) { if (Tracks[i].Id == *((int *)argument)) @@ -323,6 +354,7 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) break; } } + if (i == TrackCount) { audio_mgr_err("%s::%s track id %d unknown\n", __FILE__, __FUNCTION__, *((int *)argument)); @@ -349,10 +381,13 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) ret = cERR_AUDIO_MGR_ERROR; break; } + audio_mgr_printf(10, "%s:%s: returning %d\n", __FILE__, __FUNCTION__, ret); + return ret; } + struct Manager_s AudioManager = { "Audio", diff --git a/libeplayer3-arm/manager/chapter.c b/libeplayer3-arm/manager/chapter.c index 14167a9..4a6fc11 100644 --- a/libeplayer3-arm/manager/chapter.c +++ b/libeplayer3-arm/manager/chapter.c @@ -181,8 +181,7 @@ static int ManagerDel(Context_t *context __attribute__((unused))) TrackCount = 0; CurrentTrack = 0; - chapter_mgr_printf(10, "%s::%s return no error\n", FILENAME, - __FUNCTION__); + chapter_mgr_printf(10, "%s::%s return no error\n", FILENAME, __FUNCTION__); return cERR_CHAPTER_MGR_NO_ERROR; } diff --git a/libeplayer3-arm/manager/manager.c b/libeplayer3-arm/manager/manager.c index 7ad53e8..c2b5c23 100644 --- a/libeplayer3-arm/manager/manager.c +++ b/libeplayer3-arm/manager/manager.c @@ -72,6 +72,7 @@ void copyTrack(Track_t *to, Track_t *from) { to->Name = strdup("Unknown"); } + if (from->Encoding != NULL) { to->Encoding = strdup(from->Encoding); @@ -80,6 +81,7 @@ void copyTrack(Track_t *to, Track_t *from) { to->Encoding = strdup("Unknown"); } + if (from->language != NULL) { to->language = strdup(from->language); @@ -100,16 +102,19 @@ void freeTrack(Track_t *track) free(track->Name); track->Name = NULL; } + if (track->Encoding != NULL) { free(track->Encoding); track->Encoding = NULL; } + if (track->language != NULL) { free(track->language); track->language = NULL; } + if (track->aacbuf != NULL) { free(track->aacbuf); diff --git a/libeplayer3-arm/manager/subtitle.c b/libeplayer3-arm/manager/subtitle.c index 4cff07c..144cb5c 100644 --- a/libeplayer3-arm/manager/subtitle.c +++ b/libeplayer3-arm/manager/subtitle.c @@ -33,12 +33,14 @@ #define TRACKWRAP 20 +//#define SAM_WITH_DEBUG #ifdef SAM_WITH_DEBUG #define SUBTITLE_MGR_DEBUG #else #define SUBTITLE_MGR_SILENT #endif + #ifdef SUBTITLE_MGR_DEBUG static short debug_level = 20; @@ -256,7 +258,7 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) { if ((TrackCount > 0) && (CurrentTrack >= 0)) { - *((Track_t **)argument) = (Track_t *) & Tracks[CurrentTrack]; + *((Track_t **)argument) = (Track_t *) &Tracks[CurrentTrack]; } else { diff --git a/libeplayer3-arm/manager/video.c b/libeplayer3-arm/manager/video.c index adaa841..8a94d4a 100644 --- a/libeplayer3-arm/manager/video.c +++ b/libeplayer3-arm/manager/video.c @@ -84,6 +84,7 @@ static void (* updatedTrackInfoFnc)(void) = NULL; static int ManagerAdd(Context_t *context, Track_t track) { video_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + if (Tracks == NULL) { Tracks = malloc(sizeof(Track_t) * TRACKWRAP); @@ -93,11 +94,13 @@ static int ManagerAdd(Context_t *context, Track_t track) Tracks[i].Id = -1; } } + if (Tracks == NULL) { video_mgr_err("%s:%s malloc failed\n", __FILE__, __FUNCTION__); return cERR_VIDEO_MGR_ERROR; } + int i; for (i = 0; i < TRACKWRAP; i++) { @@ -107,6 +110,7 @@ static int ManagerAdd(Context_t *context, Track_t track) return cERR_VIDEO_MGR_NO_ERROR; } } + if (TrackCount < TRACKWRAP) { copyTrack(&Tracks[TrackCount], &track); @@ -117,10 +121,12 @@ static int ManagerAdd(Context_t *context, Track_t track) video_mgr_err("%s:%s TrackCount out if range %d - %d\n", __FILE__, __FUNCTION__, TrackCount, TRACKWRAP); return cERR_VIDEO_MGR_ERROR; } + if (TrackCount > 0) { context->playback->isVideo = 1; } + video_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); return cERR_VIDEO_MGR_NO_ERROR; } @@ -129,15 +135,19 @@ static char **ManagerList(Context_t *context __attribute__((unused))) { int i = 0, j = 0; char **tracklist = NULL; + video_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + if (Tracks != NULL) { tracklist = malloc(sizeof(char *) * ((TrackCount * 2) + 1)); + if (tracklist == NULL) { video_mgr_err("%s:%s malloc failed\n", __FILE__, __FUNCTION__); return NULL; } + for (i = 0, j = 0; i < TrackCount; i++, j += 2) { if (Tracks[i].pending) @@ -152,6 +162,7 @@ static char **ManagerList(Context_t *context __attribute__((unused))) } tracklist[j] = NULL; } + video_mgr_printf(10, "%s::%s return %p (%d - %d)\n", __FILE__, __FUNCTION__, tracklist, j, TrackCount); return tracklist; } @@ -159,7 +170,9 @@ static char **ManagerList(Context_t *context __attribute__((unused))) static int ManagerDel(Context_t *context) { int i = 0; + video_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + if (Tracks != NULL) { for (i = 0; i < TrackCount; i++) @@ -174,9 +187,11 @@ static int ManagerDel(Context_t *context) video_mgr_err("%s::%s nothing to delete!\n", __FILE__, __FUNCTION__); return cERR_VIDEO_MGR_ERROR; } + TrackCount = 0; CurrentTrack = 0; context->playback->isVideo = 0; + video_mgr_printf(10, "%s::%s return no error\n", __FILE__, __FUNCTION__); return cERR_VIDEO_MGR_NO_ERROR; } @@ -184,7 +199,9 @@ static int ManagerDel(Context_t *context) static int Command(Context_t *context, ManagerCmd_t command, void *argument) { int ret = cERR_VIDEO_MGR_NO_ERROR; + video_mgr_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + switch (command) { case MANAGER_ADD: @@ -240,9 +257,10 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) case MANAGER_GET_TRACK: { video_mgr_printf(20, "%s::%s MANAGER_GET_TRACK\n", __FILE__, __FUNCTION__); + if ((TrackCount > 0) && (CurrentTrack >= 0)) { - *((Track_t **)argument) = (Track_t *) & Tracks[CurrentTrack]; + *((Track_t **)argument) = (Track_t *) &Tracks[CurrentTrack]; } else { @@ -285,6 +303,7 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) break; } } + if (i == TrackCount) { video_mgr_err("%s::%s track id %d unknown\n", __FILE__, __FUNCTION__, *((int *)argument)); @@ -322,10 +341,12 @@ static int Command(Context_t *context, ManagerCmd_t command, void *argument) ret = cERR_VIDEO_MGR_ERROR; break; } + video_mgr_printf(10, "%s:%s: returning %d\n", __FILE__, __FUNCTION__, ret); return ret; } + struct Manager_s VideoManager = { "Video", diff --git a/libeplayer3-arm/output/linuxdvb_buffering.c b/libeplayer3-arm/output/linuxdvb_buffering.c index 343296d..2fc472f 100644 --- a/libeplayer3-arm/output/linuxdvb_buffering.c +++ b/libeplayer3-arm/output/linuxdvb_buffering.c @@ -41,13 +41,15 @@ /* ***************************** */ /* Types */ /* ***************************** */ -typedef enum OutputType_e{ +typedef enum OutputType_e +{ OUTPUT_UNK, OUTPUT_AUDIO, OUTPUT_VIDEO, } OutputType_t; -typedef struct BufferingNode_s { +typedef struct BufferingNode_s +{ uint32_t dataSize; OutputType_t dataType; struct BufferingNode_s *next; @@ -56,8 +58,8 @@ typedef struct BufferingNode_s { /* ***************************** */ /* Makros/Constants */ /* ***************************** */ -#define cERR_LINUX_DVB_BUFFERING_NO_ERROR 0 -#define cERR_LINUX_DVB_BUFFERING_ERROR -1 +#define cERR_LINUX_DVB_BUFFERING_NO_ERROR 0 +#define cERR_LINUX_DVB_BUFFERING_ERROR -1 //#define SAM_WITH_DEBUG #ifdef SAM_WITH_DEBUG @@ -83,8 +85,9 @@ if (debug_level >= level) printf("[%s:%d:%s] " fmt, __FILE__, __LINE__, __FUNCTI #endif /* ***************************** */ -/* Varaibles */ +/* Variables */ /* ***************************** */ + static pthread_t bufferingThread; static pthread_mutex_t bufferingMtx; static pthread_cond_t bufferingExitCond; @@ -108,46 +111,54 @@ static int g_pfd[2] = {-1, -1}; /* ***************************** */ /* MISC Functions */ /* ***************************** */ + static void WriteWakeUp() { write(g_pfd[1], "x", 1); } -/* **************************** */ -/* Worker Thread */ -/* **************************** */ -static void LinuxDvbBuffThread(Context_t *context) +/* ***************************** */ +/* Worker Thread */ +/* ***************************** */ + +static void LinuxDvbBuffThread(Context_t *context) { int flags = 0; static BufferingNode_t *nodePtr = NULL; buff_printf(20, "ENTER\n"); - + if (pipe(g_pfd) == -1) { buff_err("critical error\n"); } + /* Make read and write ends of pipe nonblocking */ if ((flags = fcntl(g_pfd[0], F_GETFL)) == -1) { buff_err("critical error\n"); } + /* Make read end nonblocking */ flags |= O_NONBLOCK; if (fcntl(g_pfd[0], F_SETFL, flags) == -1) { buff_err("critical error\n"); } + if ((flags = fcntl(g_pfd[1], F_GETFL)) == -1) { buff_err("critical error\n"); } + /* Make write end nonblocking */ flags |= O_NONBLOCK; if (fcntl(g_pfd[1], F_SETFL, flags) == -1) { buff_err("critical error\n"); } + PlaybackDieNowRegisterCallback(WriteWakeUp); + while (0 == PlaybackDieNow(0)) { pthread_mutex_lock(&bufferingMtx); @@ -158,11 +169,11 @@ static void LinuxDvbBuffThread(Context_t *context) /* signal that we free some space in queue */ pthread_cond_signal(&bufferingDataConsumedCond); } - + if (!bufferingQueueHead) { assert(bufferingQueueTail == NULL); - + /* Queue is empty we need to wait for data to be added */ pthread_cond_wait(&bufferingdDataAddedCond, &bufferingMtx); pthread_mutex_unlock(&bufferingMtx); @@ -176,7 +187,7 @@ static void LinuxDvbBuffThread(Context_t *context) { bufferingQueueTail = NULL; } - + if (bufferingDataSize >= (nodePtr->dataSize + sizeof(BufferingNode_t))) { bufferingDataSize -= (nodePtr->dataSize + sizeof(BufferingNode_t)); @@ -188,12 +199,12 @@ static void LinuxDvbBuffThread(Context_t *context) } } pthread_mutex_unlock(&bufferingMtx); - + /* We will write data without mutex - * this have some disadvantage because we can - * write some portion of data after LinuxDvbBuffFlush, - * for example after seek, this will be fixed later - */ + * this have some disadvantage because we can + * write some portion of data after LinuxDvbBuffFlush, + * for example after seek, this will be fixed later + */ if (nodePtr && !context->playback->isSeeking) { /* Write data to valid output */ @@ -205,11 +216,11 @@ static void LinuxDvbBuffThread(Context_t *context) } } } - + pthread_mutex_lock(&bufferingMtx); pthread_cond_signal(&bufferingExitCond); pthread_mutex_unlock(&bufferingMtx); - + buff_printf(20, "EXIT\n"); hasBufferingThreadStarted = false; close(g_pfd[0]); @@ -228,36 +239,36 @@ int32_t LinuxDvbBuffOpen(Context_t *context, char *type, int outfd) { int32_t error = 0; int32_t ret = cERR_LINUX_DVB_BUFFERING_NO_ERROR; - + buff_printf(10, "\n"); - if (!hasBufferingThreadStarted) + if (!hasBufferingThreadStarted) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if((error = pthread_create(&bufferingThread, &attr, (void *)&LinuxDvbBuffThread, context)) != 0) + if ((error = pthread_create(&bufferingThread, &attr, (void *)&LinuxDvbBuffThread, context)) != 0) { buff_printf(10, "Creating thread, error:%d:%s\n", error, strerror(error)); hasBufferingThreadStarted = false; ret = cERR_LINUX_DVB_BUFFERING_ERROR; } - else + else { buff_printf(10, "Created thread\n"); hasBufferingThreadStarted = true; /* init synchronization prymitives */ pthread_mutex_init(&bufferingMtx, NULL); - + pthread_cond_init(&bufferingExitCond, NULL); pthread_cond_init(&bufferingDataConsumedCond, NULL); pthread_cond_init(&bufferingdDataAddedCond, NULL); } } - + if (!ret) { if (!strcmp("video", type) && -1 == videofd) @@ -281,21 +292,22 @@ int32_t LinuxDvbBuffOpen(Context_t *context, char *type, int outfd) int32_t LinuxDvbBuffClose(Context_t *context __attribute__((unused))) { int32_t ret = 0; - + buff_printf(10, "\n"); videofd = -1; audiofd = -1; - - if (hasBufferingThreadStarted) + + if (hasBufferingThreadStarted) { struct timespec max_wait = {0, 0}; - - /* WakeUp if we are waiting in the write */ + + /* WakeUp if we are waiting in the write */ WriteWakeUp(); - + pthread_mutex_lock(&bufferingMtx); - /* wake up if thread is waiting for data */ + /* wake up if thread is waiting for data */ pthread_cond_signal(&bufferingdDataAddedCond); + /* wait for thread end */ clock_gettime(CLOCK_REALTIME, &max_wait); max_wait.tv_sec += 1; @@ -305,9 +317,9 @@ int32_t LinuxDvbBuffClose(Context_t *context __attribute__((unused))) if (!hasBufferingThreadStarted) { /* destroy synchronization prymitives? - * for a moment, we'll exit linux process, - * so the system will do this for us - */ + * for a moment, we'll exit linux process, + * so the system will do this for us + */ /* pthread_mutex_destroy(&bufferingMtx); pthread_cond_destroy(&bufferingDataConsumedCond); @@ -315,7 +327,7 @@ int32_t LinuxDvbBuffClose(Context_t *context __attribute__((unused))) */ } } - + ret = hasBufferingThreadStarted ? cERR_LINUX_DVB_BUFFERING_ERROR : cERR_LINUX_DVB_BUFFERING_NO_ERROR; buff_printf(10, "exiting with value %d\n", ret); @@ -326,46 +338,50 @@ int32_t LinuxDvbBuffFlush(Context_t *context __attribute__((unused))) { static BufferingNode_t *nodePtr = NULL; buff_printf(40, "ENTER bufferingQueueHead[%p]\n", bufferingQueueHead); - + /* signal if we are waiting for write to DVB decoders */ WriteWakeUp(); pthread_mutex_lock(&bufferingMtx); while (bufferingQueueHead) { - nodePtr = bufferingQueueHead; - bufferingQueueHead = nodePtr->next; - bufferingDataSize -= (nodePtr->dataSize + sizeof(BufferingNode_t)); - free(nodePtr); + nodePtr = bufferingQueueHead; + bufferingQueueHead = nodePtr->next; + bufferingDataSize -= (nodePtr->dataSize + sizeof(BufferingNode_t)); + free(nodePtr); } bufferingQueueHead = NULL; bufferingQueueTail = NULL; buff_printf(40, "bufferingDataSize [%u]\n", bufferingDataSize); assert(bufferingDataSize == 0); bufferingDataSize = 0; - + /* signal that queue is empty */ pthread_cond_signal(&bufferingDataConsumedCond); pthread_mutex_unlock(&bufferingMtx); buff_printf(40, "EXIT\n"); + return 0; } int32_t LinuxDvbBuffResume(Context_t *context __attribute__((unused))) { - /* signal if we are waiting for write to DVB decoders */ + /* signal if we are waiting for write to DVB decoders + * + */ WriteWakeUp(); + return 0; } -ssize_t BufferingWriteV(int fd, const struct iovec *iov, size_t ic) +ssize_t BufferingWriteV(int fd, const struct iovec *iov, size_t ic) { OutputType_t dataType = OUTPUT_UNK; BufferingNode_t *nodePtr = NULL; uint8_t *dataPtr = NULL; uint32_t chunkSize = 0; uint32_t i = 0; - + buff_printf(60, "ENTER\n"); if (fd == videofd) { @@ -382,13 +398,13 @@ ssize_t BufferingWriteV(int fd, const struct iovec *iov, size_t ic) buff_err("Unknown output type\n"); return cERR_LINUX_DVB_BUFFERING_ERROR; } - - for (i=0; inext = nodePtr; bufferingQueueTail = nodePtr; } - + bufferingDataSize += chunkSize; chunkSize -= sizeof(BufferingNode_t); nodePtr->dataSize = chunkSize; nodePtr->dataType = dataType; nodePtr->next = NULL; - + /* signal that we added some data to queue */ pthread_cond_signal(&bufferingdDataAddedCond); break; diff --git a/libeplayer3-arm/output/linuxdvb_mipsel.c b/libeplayer3-arm/output/linuxdvb_mipsel.c index 4335399..f4acac6 100644 --- a/libeplayer3-arm/output/linuxdvb_mipsel.c +++ b/libeplayer3-arm/output/linuxdvb_mipsel.c @@ -50,9 +50,7 @@ /* Makros/Constants */ /* ***************************** */ -// SULGE DEBUG //#define SAM_WITH_DEBUG - #ifdef SAM_WITH_DEBUG #define LINUXDVB_DEBUG static unsigned short debug_level = 20; @@ -64,15 +62,15 @@ static const char FILENAME[] = __FILE__; #ifdef LINUXDVB_DEBUG #define linuxdvb_printf(level, fmt, x...) do { \ -if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x ); } while (0) +if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0) #else -#define linuxdvb_printf(level, fmt, x...) +#define linuxdvb_printf(x...) #endif #ifndef LINUXDVB_SILENT #define linuxdvb_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0) #else -#define linuxdvb_err(fmt, x...) +#define linuxdvb_err(x...) #endif #define cERR_LINUXDVB_NO_ERROR 0 @@ -108,10 +106,11 @@ int32_t LinuxDvbBuffResume(Context_t *context); ssize_t BufferingWriteV(int fd, const struct iovec *iov, size_t ic); int32_t WriteSetBufferingSize(const uint32_t bufferSize); + int LinuxDvbStop(Context_t *context, char *type); /* ***************************** */ -/* Functions */ +/* MISC Functions */ /* ***************************** */ void getLinuxDVBMutex(const char *filename __attribute__((unused)), const char *function __attribute__((unused)), int line __attribute__((unused))) @@ -137,53 +136,67 @@ int LinuxDvbOpen(Context_t *context __attribute__((unused)), char *type) { uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if (video && videofd < 0) { videofd = open(VIDEODEV, O_RDWR | O_CLOEXEC); + if (videofd < 0) { linuxdvb_err("failed to open %s - errno %d, %s\n", VIDEODEV, errno, strerror(errno)); + linuxdvb_err("%s\n",); return cERR_LINUXDVB_ERROR; } + if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) { linuxdvb_err("VIDEO_CLEAR_BUFFER: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(videofd, VIDEO_SELECT_SOURCE, (void *)VIDEO_SOURCE_MEMORY) == -1) { linuxdvb_err("VIDEO_SELECT_SOURCE: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(videofd, VIDEO_FREEZE) == -1) { linuxdvb_err("VIDEO_FREEZE: ERROR %d, %s\n", errno, strerror(errno)); } + if (isBufferedOutput) LinuxDvbBuffOpen(context, type, videofd); } if (audio && audiofd < 0) { audiofd = open(AUDIODEV, O_RDWR | O_CLOEXEC); + if (audiofd < 0) { linuxdvb_err("failed to open %s - errno %d, %s\n", AUDIODEV, errno, strerror(errno)); return cERR_LINUXDVB_ERROR; } + if (ioctl(audiofd, AUDIO_CLEAR_BUFFER) == -1) { linuxdvb_err("AUDIO_CLEAR_BUFFER: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(audiofd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY) == -1) { linuxdvb_err("AUDIO_SELECT_SOURCE: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(audiofd, AUDIO_PAUSE) == -1) { linuxdvb_err("AUDIO_PAUSE: ERROR %d, %s\n", errno, strerror(errno)); } + if (isBufferedOutput) LinuxDvbBuffOpen(context, type, audiofd); } + return cERR_LINUXDVB_NO_ERROR; } @@ -191,15 +204,20 @@ int LinuxDvbClose(Context_t *context, char *type) { uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + /* closing stand alone is not allowed, so prevent * user from closing and don't call stop. stop will * set default values for us (speed and so on). */ LinuxDvbStop(context, type); + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (isBufferedOutput) LinuxDvbBuffClose(context); + if (video && videofd != -1) { close(videofd); @@ -210,6 +228,7 @@ int LinuxDvbClose(Context_t *context, char *type) close(audiofd); audiofd = -1; } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); return cERR_LINUXDVB_NO_ERROR; } @@ -218,14 +237,19 @@ int LinuxDvbPlay(Context_t *context, char *type) { int ret = cERR_LINUXDVB_NO_ERROR; Writer_t *writer; + uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if (video && videofd != -1) { char *Encoding = NULL; context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(10, "V %s\n", Encoding); + writer = getWriter(Encoding); if (writer == NULL) { @@ -242,15 +266,18 @@ int LinuxDvbPlay(Context_t *context, char *type) } } free(Encoding); + if (0 != ioctl(videofd, VIDEO_PLAY)) { linuxdvb_err("VIDEO_PLAY: ERROR %d, %s\n", errno, strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + if (ioctl(videofd, VIDEO_CONTINUE) == -1) { linuxdvb_err("VIDEO_CONTINUE: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) { linuxdvb_err("VIDEO_CLEAR_BUFFER: ERROR %d, %s\n", errno, strerror(errno)); @@ -260,8 +287,11 @@ int LinuxDvbPlay(Context_t *context, char *type) { char *Encoding = NULL; context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(20, "0 A %s\n", Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("cannot found writer for encoding %s using default\n", Encoding); @@ -276,11 +306,13 @@ int LinuxDvbPlay(Context_t *context, char *type) ret = cERR_LINUXDVB_ERROR; } } + if (ioctl(audiofd, AUDIO_PLAY) < 0) { linuxdvb_err("AUDIO_PLAY: ERROR %d, %s\n", errno, strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + if (ioctl(audiofd, AUDIO_CONTINUE) < 0) { linuxdvb_err("AUDIO_CONTINUE: ERROR %d, %s\n", errno, strerror(errno)); @@ -288,6 +320,7 @@ int LinuxDvbPlay(Context_t *context, char *type) } free(Encoding); } + ret = cERR_LINUXDVB_NO_ERROR; return ret; //return 0; @@ -298,19 +331,24 @@ int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type) int ret = cERR_LINUXDVB_NO_ERROR; unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) { linuxdvb_err("VIDEO_CLEAR_BUFFER: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(videofd, VIDEO_STOP) == -1) { linuxdvb_err("VIDEO_STOP: ERROR %d, %s\n", errno, strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + ioctl(videofd, VIDEO_SLOWMOTION, 0); ioctl(videofd, VIDEO_FAST_FORWARD, 0); ioctl(videofd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX); @@ -321,6 +359,7 @@ int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type) { linuxdvb_err("AUDIO_CLEAR_BUFFER: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(audiofd, AUDIO_STOP) == -1) { linuxdvb_err("AUDIO_STOP: ERROR %d, %s\n", errno, strerror(errno)); @@ -328,7 +367,9 @@ int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type) } ioctl(audiofd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX); } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + return ret; } @@ -337,8 +378,11 @@ int LinuxDvbPause(Context_t *context __attribute__((unused)), char *type) int32_t ret = cERR_LINUXDVB_NO_ERROR; uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_FREEZE, NULL) == -1) @@ -347,6 +391,7 @@ int LinuxDvbPause(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + if (audio && audiofd != -1) { if (ioctl(audiofd, AUDIO_PAUSE, NULL) == -1) @@ -355,7 +400,9 @@ int LinuxDvbPause(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + return ret; } @@ -364,19 +411,23 @@ int LinuxDvbContinue(Context_t *context __attribute__((unused)), char *type) int32_t ret = cERR_LINUXDVB_NO_ERROR; uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if (video && videofd != -1) { if (context->playback->isForwarding == 0) { ioctl(videofd, VIDEO_FAST_FORWARD, 0); } + if (ioctl(videofd, VIDEO_CONTINUE, NULL) == -1) { linuxdvb_err("VIDEO_CONTINUE: ERROR %d, %s\n", errno, strerror(errno)); ret = cERR_LINUXDVB_ERROR; } } + if (audio && audiofd != -1) { if (ioctl(audiofd, AUDIO_CONTINUE, NULL) == -1) @@ -385,16 +436,21 @@ int LinuxDvbContinue(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + if (isBufferedOutput) LinuxDvbBuffResume(context); + linuxdvb_printf(10, "exiting\n"); + return ret; } int LinuxDvbAudioMute(Context_t *context __attribute__((unused)), char *flag) { int ret = cERR_LINUXDVB_NO_ERROR; + linuxdvb_printf(10, "\n"); + if (audiofd != -1) { if (*flag == '1') @@ -414,7 +470,9 @@ int LinuxDvbAudioMute(Context_t *context __attribute__((unused)), char *flag) } } } + linuxdvb_printf(10, "exiting\n"); + return ret; } @@ -428,8 +486,11 @@ int LinuxDvbFastForward(Context_t *context, char *type) int32_t ret = cERR_LINUXDVB_NO_ERROR; uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + if (audio) {} + linuxdvb_printf(10, "v%d a%d speed %d\n", video, audio, context->playback->Speed); + if (video && videofd != -1) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); @@ -441,6 +502,7 @@ int LinuxDvbFastForward(Context_t *context, char *type) } releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting with value %d\n", ret); return ret; } @@ -448,12 +510,16 @@ int LinuxDvbFastForward(Context_t *context, char *type) int LinuxDvbSlowMotion(Context_t *context, char *type) { int32_t ret = cERR_LINUXDVB_NO_ERROR; + uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if ((video && videofd != -1) || (audio && audiofd != -1)) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_SLOWMOTION, context->playback->SlowMotion) == -1) @@ -462,9 +528,12 @@ int LinuxDvbSlowMotion(Context_t *context, char *type) ret = cERR_LINUXDVB_ERROR; } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting with value %d\n", ret); + return ret; } @@ -480,13 +549,16 @@ int LinuxDvbAVSync(Context_t *context __attribute__((unused)), char *type __attr if (audiofd != -1) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (ioctl(audiofd, AUDIO_SET_AV_SYNC, 0) == -1) //context->playback->AVSync) == -1) { linuxdvb_err("AUDIO_SET_AV_SYNC: ERROR %d, %s\n", errno, strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + return ret; } @@ -495,10 +567,13 @@ int LinuxDvbClear(Context_t *context __attribute__((unused)), char *type) int32_t ret = cERR_LINUXDVB_NO_ERROR; uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, "LinuxDvbClear v%d a%d\n", video, audio); + if ((video && videofd != -1) || (audio && audiofd != -1)) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) @@ -515,16 +590,21 @@ int LinuxDvbClear(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting\n"); + return ret; } int LinuxDvbPts(Context_t *context __attribute__((unused)), unsigned long long int *pts) { int32_t ret = cERR_LINUXDVB_ERROR; + linuxdvb_printf(50, "\n"); + // GET_PTS is immutable call, so it can be done in parallel to other requests if (videofd > -1 && !ioctl(videofd, VIDEO_GET_PTS, (void *)&sCURRENT_PTS)) { @@ -534,6 +614,7 @@ int LinuxDvbPts(Context_t *context __attribute__((unused)), unsigned long long i { linuxdvb_err("VIDEO_GET_PTS: ERROR %d, %s\n", errno, strerror(errno)); } + if (ret != cERR_LINUXDVB_NO_ERROR) { if (audiofd > -1 && !ioctl(audiofd, AUDIO_GET_PTS, (void *)&sCURRENT_PTS)) @@ -545,10 +626,12 @@ int LinuxDvbPts(Context_t *context __attribute__((unused)), unsigned long long i linuxdvb_err("AUDIO_GET_PTS: ERROR %d, %s\n", errno, strerror(errno)); } } + if (ret != cERR_LINUXDVB_NO_ERROR) { sCURRENT_PTS = 0; } + *((unsigned long long int *)pts) = (unsigned long long int)sCURRENT_PTS; return ret; } @@ -563,26 +646,34 @@ int LinuxDvbSwitch(Context_t *context, char *type) uint8_t audio = !strcmp("audio", type); uint8_t video = !strcmp("video", type); Writer_t *writer; + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if ((video && videofd != -1) || (audio && audiofd != -1)) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (audio && audiofd != -1) { char *Encoding = NULL; if (context && context->manager && context->manager->audio) { context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(10, "A %s\n", Encoding); + writer = getWriter(Encoding); + if (ioctl(audiofd, AUDIO_STOP, NULL) == -1) { linuxdvb_err("AUDIO_STOP: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(audiofd, AUDIO_CLEAR_BUFFER) == -1) { linuxdvb_err("AUDIO_CLEAR_BUFFER: ERROR %d, %s\n", errno, strerror(errno)); } + if (writer == NULL) { linuxdvb_err("cannot found writer for encoding %s using default\n", Encoding); @@ -595,6 +686,7 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_err("AUDIO_SET_BYPASS_MODE: ERROR %d, %s\n", errno, strerror(errno)); } } + if (ioctl(audiofd, AUDIO_PLAY) == -1) { linuxdvb_err("AUDIO_PLAY: ERROR %d, %s\n", errno, strerror(errno)); @@ -606,22 +698,28 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_printf(20, "no context for Audio\n"); } } + if (video && videofd != -1) { char *Encoding = NULL; if (context && context->manager && context->manager->video) { context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + if (ioctl(videofd, VIDEO_STOP, NULL) == -1) { linuxdvb_err("VIDEO_STOP: ERROR %d, %s\n", errno, strerror(errno)); } + if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) { linuxdvb_err("VIDEO_CLEAR_BUFFER: ERROR %d, %s\n", errno, strerror(errno)); } + linuxdvb_printf(10, "V %s\n", Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("cannot found writer for encoding %s using default\n", Encoding); @@ -634,6 +732,7 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_err("VIDEO_SET_STREAMTYPE: ERROR %d, %s\n", errno, strerror(errno)); } } + if (ioctl(videofd, VIDEO_PLAY) == -1) { /* konfetti: fixme: think on this, I think we should @@ -648,42 +747,54 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_printf(20, "no context for Video\n"); } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + } + linuxdvb_printf(10, "exiting\n"); + return cERR_LINUXDVB_NO_ERROR; } static int Write(Context_t *context, void *_out) { AudioVideoOut_t *out = (AudioVideoOut_t *) _out; - int32_t ret = cERR_LINUXDVB_NO_ERROR; - int32_t res = 0; - uint8_t video = 0; - uint8_t audio = 0; - Writer_t *writer = NULL; + int32_t ret = cERR_LINUXDVB_NO_ERROR; + int32_t res = 0; + uint8_t video = 0; + uint8_t audio = 0; + Writer_t *writer = NULL; WriterAVCallData_t call; + if (out == NULL) { linuxdvb_err("null pointer passed\n"); return cERR_LINUXDVB_ERROR; } + video = !strcmp("video", out->type); audio = !strcmp("audio", out->type); + linuxdvb_printf(20, "DataLength=%u PrivateLength=%u Pts=%llu FrameRate=%f\n", out->len, out->extralen, out->pts, out->frameRate); linuxdvb_printf(20, "v%d a%d\n", video, audio); + if (video) { char *Encoding = NULL; context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(20, "Encoding = %s\n", Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_printf(20, "searching default writer ... %s\n", Encoding); writer = getDefaultVideoWriter(); } + if (writer == NULL) { linuxdvb_err("unknown video codec and no default writer %s\n", Encoding); @@ -734,6 +845,7 @@ static int Write(Context_t *context, void *_out) } } } + call.fd = videofd; call.data = out->data; call.len = out->len; @@ -747,11 +859,13 @@ static int Write(Context_t *context, void *_out) call.Height = out->height; call.InfoFlags = out->infoFlags; call.Version = 0; - call.WriteV = isBufferedOutput ? BufferingWriteV : writev_with_retry; + call.WriteV = isBufferedOutput ? BufferingWriteV : writev_with_retry; + if (writer->writeData) { res = writer->writeData(&call); } + if (res < 0) { linuxdvb_err("failed to write data %d - %d\n", res, errno); @@ -759,19 +873,24 @@ static int Write(Context_t *context, void *_out) ret = cERR_LINUXDVB_ERROR; } } + free(Encoding); } else if (audio) { char *Encoding = NULL; context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(20, "%s::%s Encoding = %s\n", FILENAME, __FUNCTION__, Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_printf(20, "searching default writer ... %s\n", Encoding); writer = getDefaultAudioWriter(); } + if (writer == NULL) { linuxdvb_err("unknown audio codec %s and no default writer\n", Encoding); @@ -790,11 +909,13 @@ static int Write(Context_t *context, void *_out) call.FrameScale = out->timeScale; call.InfoFlags = out->infoFlags; call.Version = 0; - call.WriteV = isBufferedOutput ? BufferingWriteV : writev_with_retry; + call.WriteV = isBufferedOutput ? BufferingWriteV : writev_with_retry; + if (writer->writeData) { res = writer->writeData(&call); } + if (res < 0) { linuxdvb_err("failed to write data %d - %d\n", res, errno); @@ -802,8 +923,10 @@ static int Write(Context_t *context, void *_out) ret = cERR_LINUXDVB_ERROR; } } + free(Encoding); } + return ret; } @@ -812,8 +935,11 @@ static int reset(Context_t *context) int ret = cERR_LINUXDVB_NO_ERROR; Writer_t *writer; char *Encoding = NULL; + context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("unknown video codec %s\n", Encoding); @@ -823,9 +949,13 @@ static int reset(Context_t *context) { writer->reset(); } + free(Encoding); + context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("unknown video codec %s\n", Encoding); @@ -835,16 +965,21 @@ static int reset(Context_t *context) { writer->reset(); } + free(Encoding); + if (isBufferedOutput) LinuxDvbBuffFlush(context); + return ret; } static int Command(Context_t *context, OutputCmd_t command, void *argument) { int ret = cERR_LINUXDVB_NO_ERROR; + linuxdvb_printf(50, "Command %d\n", command); + switch (command) { case OUTPUT_OPEN: @@ -946,7 +1081,7 @@ static int Command(Context_t *context, OutputCmd_t command, void *argument) ret = cERR_LINUXDVB_ERROR; if (!isBufferedOutput) { - uint32_t bufferSize = *((uint32_t*)argument); + uint32_t bufferSize = *((uint32_t *)argument); ret = cERR_LINUXDVB_NO_ERROR; if (bufferSize > 0) { @@ -961,7 +1096,9 @@ static int Command(Context_t *context, OutputCmd_t command, void *argument) ret = cERR_LINUXDVB_ERROR; break; } + linuxdvb_printf(50, "exiting with value %d\n", ret); + return ret; } diff --git a/libeplayer3-arm/output/linuxdvb_sh4.c b/libeplayer3-arm/output/linuxdvb_sh4.c index efbc39c..1eb6d23 100644 --- a/libeplayer3-arm/output/linuxdvb_sh4.c +++ b/libeplayer3-arm/output/linuxdvb_sh4.c @@ -70,6 +70,7 @@ if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); #define linuxdvb_err(x...) #endif + #define cERR_LINUXDVB_NO_ERROR 0 #define cERR_LINUXDVB_ERROR -1 @@ -99,84 +100,103 @@ pthread_mutex_t LinuxDVBmutex; int LinuxDvbStop(Context_t *context, char *type); /* ***************************** */ -/* Functions */ +/* MISC Functions */ /* ***************************** */ void getLinuxDVBMutex(const char *filename __attribute__((unused)), const char *function __attribute__((unused)), int line __attribute__((unused))) { + linuxdvb_printf(250, "requesting mutex\n"); + pthread_mutex_lock(&LinuxDVBmutex); + linuxdvb_printf(250, "received mutex\n"); } void releaseLinuxDVBMutex(const char *filename __attribute__((unused)), const char *function __attribute__((unused)), int line __attribute__((unused))) { pthread_mutex_unlock(&LinuxDVBmutex); + linuxdvb_printf(250, "released mutex\n"); + } int LinuxDvbOpen(Context_t *context __attribute__((unused)), char *type) { unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if (video && videofd < 0) { videofd = open(VIDEODEV, O_RDWR); + if (videofd < 0) { linuxdvb_err("failed to open %s - errno %d\n", VIDEODEV, errno); linuxdvb_err("%s\n", strerror(errno)); return cERR_LINUXDVB_ERROR; } + if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_CLEAR_BUFFER: %s\n", strerror(errno)); } + if (ioctl(videofd, VIDEO_SELECT_SOURCE, (void *)VIDEO_SOURCE_MEMORY) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_SELECT_SOURCE: %s\n", strerror(errno)); } + if (ioctl(videofd, VIDEO_SET_STREAMTYPE, (void *)STREAM_TYPE_PROGRAM) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_SET_STREAMTYPE: %s\n", strerror(errno)); } + if (ioctl(videofd, VIDEO_SET_SPEED, DVB_SPEED_NORMAL_PLAY) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_SET_SPEED: %s\n", strerror(errno)); } + } if (audio && audiofd < 0) { audiofd = open(AUDIODEV, O_RDWR); + if (audiofd < 0) { linuxdvb_err("failed to open %s - errno %d\n", AUDIODEV, errno); linuxdvb_err("%s\n", strerror(errno)); + if (videofd < 0) close(videofd); return cERR_LINUXDVB_ERROR; } + if (ioctl(audiofd, AUDIO_CLEAR_BUFFER) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_CLEAR_BUFFER: %s\n", strerror(errno)); } + if (ioctl(audiofd, AUDIO_SELECT_SOURCE, (void *)AUDIO_SOURCE_MEMORY) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_SELECT_SOURCE: %s\n", strerror(errno)); } + if (ioctl(audiofd, AUDIO_SET_STREAMTYPE, (void *)STREAM_TYPE_PROGRAM) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_SET_STREAMTYPE: %s\n", strerror(errno)); } } + return cERR_LINUXDVB_NO_ERROR; } @@ -184,13 +204,17 @@ int LinuxDvbClose(Context_t *context, char *type) { unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + /* closing stand alone is not allowed, so prevent * user from closing and dont call stop. stop will * set default values for us (speed and so on). */ LinuxDvbStop(context, type); + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { close(videofd); @@ -201,6 +225,7 @@ int LinuxDvbClose(Context_t *context, char *type) close(audiofd); audiofd = -1; } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); return cERR_LINUXDVB_NO_ERROR; } @@ -209,15 +234,21 @@ int LinuxDvbPlay(Context_t *context, char *type) { int ret = cERR_LINUXDVB_NO_ERROR; Writer_t *writer; + unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if (video && videofd != -1) { char *Encoding = NULL; context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(10, "V %s\n", Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("cannot found writer for encoding %s using default\n", Encoding); @@ -238,6 +269,7 @@ int LinuxDvbPlay(Context_t *context, char *type) ret = cERR_LINUXDVB_ERROR; } } + if (ioctl(videofd, VIDEO_PLAY, NULL) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); @@ -250,8 +282,11 @@ int LinuxDvbPlay(Context_t *context, char *type) { char *Encoding = NULL; context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(20, "0 A %s\n", Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("cannot found writer for encoding %s using default\n", Encoding); @@ -272,6 +307,7 @@ int LinuxDvbPlay(Context_t *context, char *type) ret = -1; } } + if (ioctl(audiofd, AUDIO_PLAY, NULL) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); @@ -280,6 +316,7 @@ int LinuxDvbPlay(Context_t *context, char *type) } free(Encoding); } + return ret; } @@ -288,8 +325,11 @@ int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type) int ret = cERR_LINUXDVB_NO_ERROR; unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) @@ -297,6 +337,7 @@ int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type) linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_CLEAR_BUFFER: %s\n", strerror(errno)); } + /* set back to normal speed (end trickmodes) */ if (ioctl(videofd, VIDEO_SET_SPEED, DVB_SPEED_NORMAL_PLAY) == -1) { @@ -317,6 +358,7 @@ int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type) linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_CLEAR_BUFFER: %s\n", strerror(errno)); } + /* set back to normal speed (end trickmodes) */ if (ioctl(audiofd, AUDIO_SET_SPEED, DVB_SPEED_NORMAL_PLAY) == -1) { @@ -330,7 +372,9 @@ int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + return ret; } @@ -339,8 +383,11 @@ int LinuxDvbPause(Context_t *context __attribute__((unused)), char *type) int ret = cERR_LINUXDVB_NO_ERROR; unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_FREEZE, NULL) == -1) @@ -359,7 +406,9 @@ int LinuxDvbPause(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + return ret; } @@ -368,7 +417,9 @@ int LinuxDvbContinue(Context_t *context __attribute__((unused)), char *type) int ret = cERR_LINUXDVB_NO_ERROR; unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_CONTINUE, NULL) == -1) @@ -387,7 +438,10 @@ int LinuxDvbContinue(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + linuxdvb_printf(10, "exiting\n"); + + return ret; } @@ -395,20 +449,26 @@ int LinuxDvbReverseDiscontinuity(Context_t *context __attribute__((unused)), int { int ret = cERR_LINUXDVB_NO_ERROR; int dis_type = VIDEO_DISCONTINUITY_CONTINUOUS_REVERSE | *surplus; + linuxdvb_printf(50, "\n"); + if (ioctl(videofd, VIDEO_DISCONTINUITY, (void *) dis_type) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_DISCONTINUITY: %s\n", strerror(errno)); } + linuxdvb_printf(50, "exiting\n"); + return ret; } int LinuxDvbAudioMute(Context_t *context __attribute__((unused)), char *flag) { int ret = cERR_LINUXDVB_NO_ERROR; + linuxdvb_printf(10, "\n"); + if (audiofd != -1) { if (*flag == '1') @@ -436,18 +496,24 @@ int LinuxDvbAudioMute(Context_t *context __attribute__((unused)), char *flag) } } } + linuxdvb_printf(10, "exiting\n"); + return ret; } + int LinuxDvbFlush(Context_t *context __attribute__((unused)), char *type) { unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if ((video && videofd != -1) || (audio && audiofd != -1)) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_FLUSH, NULL) == -1) @@ -456,6 +522,7 @@ int LinuxDvbFlush(Context_t *context __attribute__((unused)), char *type) linuxdvb_err("VIDEO_FLUSH: %s\n", strerror(errno)); } } + if (audio && audiofd != -1) { if (ioctl(audiofd, AUDIO_FLUSH, NULL) == -1) @@ -464,9 +531,12 @@ int LinuxDvbFlush(Context_t *context __attribute__((unused)), char *type) linuxdvb_err("AUDIO_FLUSH: %s\n", strerror(errno)); } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting\n"); + return cERR_LINUXDVB_NO_ERROR; } @@ -474,22 +544,31 @@ int LinuxDvbFlush(Context_t *context __attribute__((unused)), char *type) int LinuxDvbFastForward(Context_t *context, char *type) { int ret = cERR_LINUXDVB_NO_ERROR; + unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d speed %d\n", video, audio, context->playback->Speed); + if (video && videofd != -1) { + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + /* konfetti comment: speed is a value given in skipped frames */ + if (ioctl(videofd, VIDEO_FAST_FORWARD, context->playback->Speed) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_FAST_FORWARD: %s\n", strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting with value %d\n", ret); + return ret; } #else @@ -508,38 +587,54 @@ int LinuxDvbFastForward(Context_t *context, char *type) int speedIndex; unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if (video && videofd != -1) { + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + speedIndex = context->playback->Speed % (sizeof(SpeedList) / sizeof(int)); + linuxdvb_printf(1, "speedIndex %d\n", speedIndex); + if (ioctl(videofd, VIDEO_SET_SPEED, SpeedList[speedIndex]) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_SET_SPEED: %s\n", strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + if (audio && audiofd != -1) { + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + speedIndex = context->playback->Speed % (sizeof(SpeedList) / sizeof(int)); + linuxdvb_printf(1, "speedIndex %d\n", speedIndex); + if (ioctl(audiofd, AUDIO_SET_SPEED, SpeedList[speedIndex]) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_SET_SPEED: %s\n", strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting with value %d\n", ret); + return ret; } #endif + int LinuxDvbReverse(Context_t *context __attribute__((unused)), char *type __attribute__((unused))) { int ret = cERR_LINUXDVB_NO_ERROR; @@ -549,12 +644,16 @@ int LinuxDvbReverse(Context_t *context __attribute__((unused)), char *type __att int LinuxDvbSlowMotion(Context_t *context, char *type) { int ret = cERR_LINUXDVB_NO_ERROR; + unsigned char video = !strcmp("video", type); unsigned char audio = !strcmp("audio", type); + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if ((video && videofd != -1) || (audio && audiofd != -1)) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_SLOWMOTION, context->playback->SlowMotion) == -1) @@ -564,9 +663,12 @@ int LinuxDvbSlowMotion(Context_t *context, char *type) ret = cERR_LINUXDVB_ERROR; } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting with value %d\n", ret); + return ret; } @@ -582,14 +684,17 @@ int LinuxDvbAVSync(Context_t *context, char *type __attribute__((unused))) if (audiofd != -1) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (ioctl(audiofd, AUDIO_SET_AV_SYNC, context->playback->AVSync) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_SET_AV_SYNC: %s\n", strerror(errno)); ret = cERR_LINUXDVB_ERROR; } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + return ret; } @@ -598,10 +703,13 @@ int LinuxDvbClear(Context_t *context __attribute__((unused)), char *type) int32_t ret = cERR_LINUXDVB_NO_ERROR; uint8_t video = !strcmp("video", type); uint8_t audio = !strcmp("audio", type); + linuxdvb_printf(10, ">>>>>>>>>>LinuxDvbClear v%d a%d\n", video, audio); + if ((video && videofd != -1) || (audio && audiofd != -1)) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (video && videofd != -1) { if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) @@ -620,18 +728,24 @@ int LinuxDvbClear(Context_t *context __attribute__((unused)), char *type) ret = cERR_LINUXDVB_ERROR; } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); } + linuxdvb_printf(10, "exiting\n"); + return ret; } int LinuxDvbPts(Context_t *context __attribute__((unused)), unsigned long long int *pts) { int ret = cERR_LINUXDVB_ERROR; + linuxdvb_printf(50, "\n"); + // pts is a non writting requests and can be done in parallel to other requests //getLinuxDVBMutex(FILENAME, __FUNCTION__,__LINE__); + if (videofd > -1 && !ioctl(videofd, VIDEO_GET_PTS, (void *)&sCURRENT_PTS)) { ret = cERR_LINUXDVB_NO_ERROR; @@ -640,6 +754,7 @@ int LinuxDvbPts(Context_t *context __attribute__((unused)), unsigned long long i { linuxdvb_err("VIDEO_GET_PTS: %d (%s)\n", errno, strerror(errno)); } + if (ret != cERR_LINUXDVB_NO_ERROR) { if (audiofd > -1 && !ioctl(audiofd, AUDIO_GET_PTS, (void *)&sCURRENT_PTS)) @@ -651,12 +766,16 @@ int LinuxDvbPts(Context_t *context __attribute__((unused)), unsigned long long i linuxdvb_err("AUDIO_GET_PTS: %d (%s)\n", errno, strerror(errno)); } } + if (ret != cERR_LINUXDVB_NO_ERROR) { sCURRENT_PTS = 0; } + *((unsigned long long int *)pts) = (unsigned long long int)sCURRENT_PTS; + //releaseLinuxDVBMutex(FILENAME, __FUNCTION__,__LINE__); + return ret; } @@ -664,8 +783,11 @@ int LinuxDvbGetFrameCount(Context_t *context __attribute__((unused)), unsigned l { int ret = cERR_LINUXDVB_NO_ERROR; dvb_play_info_t playInfo; + linuxdvb_printf(50, "\n"); + getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (videofd != -1) { if (ioctl(videofd, VIDEO_GET_PLAY_INFO, (void *)&playInfo) == -1) @@ -690,9 +812,12 @@ int LinuxDvbGetFrameCount(Context_t *context __attribute__((unused)), unsigned l { ret = cERR_LINUXDVB_ERROR; } + if (ret == cERR_LINUXDVB_NO_ERROR) *((unsigned long long int *)frameCount) = playInfo.frame_count; + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + return ret; } @@ -701,28 +826,38 @@ int LinuxDvbSwitch(Context_t *context, char *type) unsigned char audio = !strcmp("audio", type); unsigned char video = !strcmp("video", type); Writer_t *writer; + linuxdvb_printf(10, "v%d a%d\n", video, audio); + if ((video && videofd != -1) || (audio && audiofd != -1)) { getLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + if (audio && audiofd != -1) { char *Encoding = NULL; if (context && context->manager && context->manager->audio) { context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(10, "A %s\n", Encoding); + writer = getWriter(Encoding); + if (ioctl(audiofd, AUDIO_STOP, NULL) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_STOP: %s\n", strerror(errno)); + } + if (ioctl(audiofd, AUDIO_CLEAR_BUFFER) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("AUDIO_CLEAR_BUFFER: %s\n", strerror(errno)); + } + if (writer == NULL) { linuxdvb_err("cannot found writer for encoding %s using default\n", Encoding); @@ -741,6 +876,7 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_err("AUDIO_SET_ENCODING: %s\n", strerror(errno)); } } + if (ioctl(audiofd, AUDIO_PLAY, NULL) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); @@ -753,24 +889,30 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_printf(20, "no context for Audio\n"); } } + if (video && videofd != -1) { char *Encoding = NULL; if (context && context->manager && context->manager->video) { context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + if (ioctl(videofd, VIDEO_STOP, NULL) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_STOP: %s\n", strerror(errno)); } + if (ioctl(videofd, VIDEO_CLEAR_BUFFER) == -1) { linuxdvb_err("ioctl failed with errno %d\n", errno); linuxdvb_err("VIDEO_CLEAR_BUFFER: %s\n", strerror(errno)); } + linuxdvb_printf(10, "V %s\n", Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("cannot found writer for encoding %s using default\n", Encoding); @@ -789,6 +931,7 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_err("VIDEO_SET_ENCODING: %s\n", strerror(errno)); } } + if (ioctl(videofd, VIDEO_PLAY, NULL) == -1) { /* konfetti: fixme: think on this, I think we should @@ -804,9 +947,13 @@ int LinuxDvbSwitch(Context_t *context, char *type) linuxdvb_printf(20, "no context for Video\n"); } } + releaseLinuxDVBMutex(FILENAME, __FUNCTION__, __LINE__); + } + linuxdvb_printf(10, "exiting\n"); + return cERR_LINUXDVB_NO_ERROR; } @@ -820,27 +967,35 @@ static int Write(void *_context, void *_out) unsigned char audio = 0; Writer_t *writer; WriterAVCallData_t call; + if (out == NULL) { linuxdvb_err("null pointer passed\n"); return cERR_LINUXDVB_ERROR; } + video = !strcmp("video", out->type); audio = !strcmp("audio", out->type); + linuxdvb_printf(20, "DataLength=%u PrivateLength=%u Pts=%llu FrameRate=%f\n", out->len, out->extralen, out->pts, out->frameRate); linuxdvb_printf(20, "v%d a%d\n", video, audio); + if (video) { char *Encoding = NULL; context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(20, "Encoding = %s\n", Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_printf(20, "searching default writer ... %s\n", Encoding); writer = getDefaultVideoWriter(); } + if (writer == NULL) { linuxdvb_err("unknown video codec and no default writer %s\n", Encoding); @@ -891,6 +1046,7 @@ static int Write(void *_context, void *_out) } } } + call.fd = videofd; call.data = out->data; call.len = out->len; @@ -904,10 +1060,12 @@ static int Write(void *_context, void *_out) call.Height = out->height; call.InfoFlags = out->infoFlags; call.Version = 0; // is unsingned char + if (writer->writeData) { res = writer->writeData(&call); } + if (res < 0) { linuxdvb_err("failed to write data %d - %d\n", res, errno); @@ -915,19 +1073,24 @@ static int Write(void *_context, void *_out) ret = cERR_LINUXDVB_ERROR; } } + free(Encoding); } else if (audio) { char *Encoding = NULL; context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + linuxdvb_printf(20, "%s::%s Encoding = %s\n", FILENAME, __FUNCTION__, Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_printf(20, "searching default writer ... %s\n", Encoding); writer = getDefaultAudioWriter(); } + if (writer == NULL) { linuxdvb_err("unknown audio codec %s and no default writer\n", Encoding); @@ -946,10 +1109,12 @@ static int Write(void *_context, void *_out) call.FrameScale = out->timeScale; call.InfoFlags = out->infoFlags; call.Version = 0; /* -1; unsigned char cannot be negative */ + if (writer->writeData) { res = writer->writeData(&call); } + if (res < 0) { linuxdvb_err("failed to write data %d - %d\n", res, errno); @@ -957,8 +1122,10 @@ static int Write(void *_context, void *_out) ret = cERR_LINUXDVB_ERROR; } } + free(Encoding); } + return ret; } @@ -967,8 +1134,11 @@ static int reset(Context_t *context) int ret = cERR_LINUXDVB_NO_ERROR; Writer_t *writer; char *Encoding = NULL; + context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("unknown video codec %s\n", Encoding); @@ -978,9 +1148,13 @@ static int reset(Context_t *context) { writer->reset(); } + free(Encoding); + context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding); + writer = getWriter(Encoding); + if (writer == NULL) { linuxdvb_err("unknown video codec %s\n", Encoding); @@ -990,7 +1164,9 @@ static int reset(Context_t *context) { writer->reset(); } + free(Encoding); + return ret; } @@ -998,7 +1174,9 @@ static int Command(void *_context, OutputCmd_t command, void *argument) { Context_t *context = (Context_t *) _context; int ret = cERR_LINUXDVB_NO_ERROR; + linuxdvb_printf(50, "Command %d\n", command); + switch (command) { case OUTPUT_OPEN: @@ -1110,7 +1288,9 @@ static int Command(void *_context, OutputCmd_t command, void *argument) ret = cERR_LINUXDVB_ERROR; break; } + linuxdvb_printf(50, "exiting with value %d\n", ret); + return ret; } diff --git a/libeplayer3-arm/output/output.c b/libeplayer3-arm/output/output.c index 8c1580f..d63f30c 100644 --- a/libeplayer3-arm/output/output.c +++ b/libeplayer3-arm/output/output.c @@ -77,14 +77,16 @@ static Output_t *AvailableOutput[] = /* ***************************** */ /* ***************************** */ -/* Functions */ +/* MISC Functions */ /* ***************************** */ static void printOutputCapabilities() { int i, j; + output_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); output_printf(10, "Capabilities:\n"); + for (i = 0; AvailableOutput[i] != NULL; i++) { output_printf(10, "\t%s : ", AvailableOutput[i]->Name); @@ -103,7 +105,9 @@ static void printOutputCapabilities() static void OutputAdd(Context_t *context, char *port) { int i, j; + output_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + for (i = 0; AvailableOutput[i] != NULL; i++) { for (j = 0; AvailableOutput[i]->Capabilities[j] != NULL; j++) @@ -133,6 +137,7 @@ static void OutputAdd(Context_t *context, char *port) static void OutputDel(Context_t *context, char *port) { output_printf(10, "%s::%s\n", __FILE__, __FUNCTION__); + if (!strcmp("audio", port)) { context->output->audio = NULL; @@ -150,7 +155,9 @@ static void OutputDel(Context_t *context, char *port) static int Command(Context_t *context, OutputCmd_t command, void *argument) { int ret = cERR_OUTPUT_NO_ERROR; + output_printf(10, "%s::%s Command %d\n", __FILE__, __FUNCTION__, command); + switch (command) { case OUTPUT_OPEN: @@ -562,7 +569,9 @@ static int Command(Context_t *context, OutputCmd_t command, void *argument) ret = cERR_OUTPUT_INTERNAL_ERROR; break; } + output_printf(10, "%s::%s exiting with value %d\n", __FILE__, __FUNCTION__, ret); + return ret; } diff --git a/libeplayer3-arm/output/output_subtitle.c b/libeplayer3-arm/output/output_subtitle.c index 726d230..16fc2bb 100644 --- a/libeplayer3-arm/output/output_subtitle.c +++ b/libeplayer3-arm/output/output_subtitle.c @@ -82,6 +82,7 @@ Number, Style, Name,, MarginL, MarginR, MarginV, Effect,, Text /* Types */ /* ***************************** */ + /* ***************************** */ /* Variables */ /* ***************************** */ @@ -94,19 +95,22 @@ static int isSubtitleOpened = 0; /* ***************************** */ /* ***************************** */ -/* Functions */ +/* MISC Functions */ /* ***************************** */ static void getMutex(int line __attribute__((unused))) { subtitle_printf(100, "%d requesting mutex\n", line); + pthread_mutex_lock(&mutex); + subtitle_printf(100, "%d received mutex\n", line); } static void releaseMutex(int line __attribute__((unused))) { pthread_mutex_unlock(&mutex); + subtitle_printf(100, "%d released mutex\n", line); } @@ -176,6 +180,7 @@ static char *json_string_escape(char *str) *ptr1++ = *ptr2; break; } + ++ptr2; } *ptr1 = '\0'; @@ -193,25 +198,32 @@ static int Write(Context_t *context, void *data) char *Encoding = NULL; SubtitleOut_t *out = NULL; int32_t curtrackid = -1; + subtitle_printf(10, "\n"); + if (data == NULL) { subtitle_err("null pointer passed\n"); return cERR_SUBTITLE_ERROR; } + out = (SubtitleOut_t *) data; + context->manager->subtitle->Command(context, MANAGER_GET, &curtrackid); if (curtrackid != (int32_t)out->trackId) { Flush(); } context->manager->subtitle->Command(context, MANAGER_GETENCODING, &Encoding); + if (Encoding == NULL) { subtitle_err("encoding unknown\n"); return cERR_SUBTITLE_ERROR; } + subtitle_printf(20, "Encoding:%s Text:%s Len:%d\n", Encoding, (const char *) out->data, out->len); + if (!strncmp("S_TEXT/SUBRIP", Encoding, 13)) { fprintf(stderr, "{\"s_a\":{\"id\":%d,\"s\":%lld,\"e\":%lld,\"t\":\"%s\"}}\n", out->trackId, out->pts / 90, out->pts / 90 + out->durationMS, json_string_escape((char *)out->data)); @@ -225,6 +237,7 @@ static int Write(Context_t *context, void *data) subtitle_err("unknown encoding %s\n", Encoding); return cERR_SUBTITLE_ERROR; } + subtitle_printf(10, "<\n"); return cERR_SUBTITLE_NO_ERROR; } @@ -232,15 +245,21 @@ static int Write(Context_t *context, void *data) static int32_t subtitle_Open(Context_t *context __attribute__((unused))) { //uint32_t i = 0 ; + subtitle_printf(10, "\n"); + if (isSubtitleOpened == 1) { subtitle_err("already opened! ignoring\n"); return cERR_SUBTITLE_ERROR; } + getMutex(__LINE__); + isSubtitleOpened = 1; + releaseMutex(__LINE__); + subtitle_printf(10, "<\n"); return cERR_SUBTITLE_NO_ERROR; } @@ -248,18 +267,26 @@ static int32_t subtitle_Open(Context_t *context __attribute__((unused))) static int32_t subtitle_Close(Context_t *context __attribute__((unused))) { //uint32_t i = 0 ; + subtitle_printf(10, "\n"); + getMutex(__LINE__); + isSubtitleOpened = 0; + releaseMutex(__LINE__); + subtitle_printf(10, "<\n"); + return cERR_SUBTITLE_NO_ERROR; } static int Command(Context_t *context, OutputCmd_t command, void *argument __attribute__((unused))) { int ret = cERR_SUBTITLE_NO_ERROR; + subtitle_printf(50, "%d\n", command); + switch (command) { case OUTPUT_OPEN: @@ -312,10 +339,12 @@ static int Command(Context_t *context, OutputCmd_t command, void *argument __att ret = cERR_SUBTITLE_ERROR; break; } + subtitle_printf(50, "exiting with value %d\n", ret); return ret; } + static char *SubtitleCapabilitis[] = { "subtitle", NULL }; Output_t SubtitleOutput = diff --git a/libeplayer3-arm/output/writer/common/misc.c b/libeplayer3-arm/output/writer/common/misc.c index c9c18af..71c5ec1 100644 --- a/libeplayer3-arm/output/writer/common/misc.c +++ b/libeplayer3-arm/output/writer/common/misc.c @@ -69,12 +69,15 @@ void PutBits(BitPacker_t *ld, unsigned int code, unsigned int length) { unsigned int bit_buf; unsigned int bit_left; + bit_buf = ld->BitBuffer; bit_left = ld->Remaining; + #ifdef DEBUG_PUTBITS if (ld->debug) dprintf("code = %d, length = %d, bit_buf = 0x%x, bit_left = %d\n", code, length, bit_buf, bit_left); #endif /* DEBUG_PUTBITS */ + if (length < bit_left) { /* fits into current buffer */ @@ -96,10 +99,12 @@ void PutBits(BitPacker_t *ld, unsigned int code, unsigned int length) bit_left = 32 - length; bit_buf = code; } + #ifdef DEBUG_PUTBITS if (ld->debug) dprintf("bit_left = %d, bit_buf = 0x%x\n", bit_left, bit_buf); #endif /* DEBUG_PUTBITS */ + /* writeback */ ld->BitBuffer = bit_buf; ld->Remaining = bit_left; diff --git a/libeplayer3-arm/output/writer/common/pes.c b/libeplayer3-arm/output/writer/common/pes.c index fea8dc3..e4788c5 100644 --- a/libeplayer3-arm/output/writer/common/pes.c +++ b/libeplayer3-arm/output/writer/common/pes.c @@ -57,6 +57,7 @@ /* Types */ /* ***************************** */ + /* ***************************** */ /* Varaibles */ /* ***************************** */ @@ -73,25 +74,32 @@ int32_t InsertVideoPrivateDataHeader(uint8_t *data, int32_t payload_size) { BitPacker_t ld2 = {data, 0, 32}; int32_t i = 0; + PutBits(&ld2, PES_PRIVATE_DATA_FLAG, 8); PutBits(&ld2, payload_size & 0xff, 8); PutBits(&ld2, (payload_size >> 8) & 0xff, 8); PutBits(&ld2, (payload_size >> 16) & 0xff, 8); + for (i = 4; i < (PES_PRIVATE_DATA_LENGTH + 1); i++) { PutBits(&ld2, 0, 8); } + FlushBits(&ld2); + return PES_PRIVATE_DATA_LENGTH + 1; + } int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t pts, int32_t pic_start_code) { BitPacker_t ld2 = {data, 0, 32}; + if (size > (MAX_PES_PACKET_SIZE - 13)) { size = -1; // unbounded } + PutBits(&ld2, 0x0, 8); PutBits(&ld2, 0x0, 8); PutBits(&ld2, 0x1, 8); // Start Code @@ -113,6 +121,7 @@ int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t PutBits(&ld2, 0x0, 1); // Copyright PutBits(&ld2, 0x0, 1); // Original or Copy //7 = 6+1 + if (pts != INVALID_PTS_VALUE) { PutBits(&ld2, 0x2, 2); @@ -121,6 +130,7 @@ int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t { PutBits(&ld2, 0x0, 2); // PTS_DTS flag } + PutBits(&ld2, 0x0, 1); // ESCR_flag PutBits(&ld2, 0x0, 1); // ES_rate_flag PutBits(&ld2, 0x0, 1); // DSM_trick_mode_flag @@ -128,6 +138,7 @@ int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t PutBits(&ld2, 0x0, 1); // PES_CRC_flag PutBits(&ld2, 0x0, 1); // PES_extension_flag //8 = 7+1 + if (pts != INVALID_PTS_VALUE) { PutBits(&ld2, 0x5, 8); @@ -137,6 +148,7 @@ int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t PutBits(&ld2, 0x0, 8); // PES_header_data_length } //9 = 8+1 + if (pts != INVALID_PTS_VALUE) { PutBits(&ld2, 0x2, 4); @@ -148,6 +160,7 @@ int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t PutBits(&ld2, 0x1, 1); } //14 = 9+5 + if (pic_start_code) { PutBits(&ld2, 0x0, 8); @@ -157,6 +170,8 @@ int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t PutBits(&ld2, (pic_start_code >> 8) & 0xff, 8); // For any extra information (like in mpeg4p2, the pic_start_code) //14 + 4 = 18 } + FlushBits(&ld2); + return (ld2.Ptr - data); } diff --git a/libeplayer3-arm/output/writer/mipsel/aac.c b/libeplayer3-arm/output/writer/mipsel/aac.c index 90b48c7..4ec234b 100644 --- a/libeplayer3-arm/output/writer/mipsel/aac.c +++ b/libeplayer3-arm/output/writer/mipsel/aac.c @@ -143,7 +143,7 @@ LATMContext *pLATMCtx = NULL; /* ***************************** */ /* ***************************** */ -/* Functions */ +/* MISC Functions */ /* ***************************** */ static int reset() @@ -159,16 +159,19 @@ static int reset() static int _writeData(WriterAVCallData_t *call, int type) { aac_printf(10, "\n _writeData type[%d]\n", type); + if (call == NULL) { aac_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len < 8)) { aac_err("parsing Data with missing AAC header. ignoring...\n"); return 0; } + /* simple validation */ if (0 == type) // check ADTS header { @@ -195,9 +198,13 @@ static int _writeData(WriterAVCallData_t *call, int type) return 0; } } + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + aac_printf(10, "AudioPts %lld\n", call->Pts); + unsigned int HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = HeaderLength; @@ -209,31 +216,37 @@ static int _writeData(WriterAVCallData_t *call, int type) static int writeDataADTS(WriterAVCallData_t *call) { aac_printf(10, "\n"); + if (call == NULL) { aac_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { aac_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { aac_err("file pointer < 0. ignoring ...\n"); return 0; } + if ((call->private_data && 0 == strncmp("ADTS", (const char *)call->private_data, call->private_size)) || HasADTSHeader(call->data, call->len)) { //printf("%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", call->data[0], call->data[1], call->data[2], call->data[3], call->data[4], call->data[5], call->data[6], call->data[7]); return _writeData(call, 0); } + uint32_t PacketLength = call->len + AAC_HEADER_LENGTH; uint8_t PesHeader[PES_MAX_HEADER_SIZE + AAC_HEADER_LENGTH]; uint32_t headerSize = InsertPesHeader(PesHeader, PacketLength, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); uint8_t *pExtraData = &PesHeader[headerSize]; + aac_printf(10, "AudioPts %lld\n", call->Pts); if (call->private_data == NULL) { @@ -244,6 +257,7 @@ static int writeDataADTS(WriterAVCallData_t *call) { memcpy(pExtraData, call->private_data, AAC_HEADER_LENGTH); } + pExtraData[3] &= 0xC0; /* frame size over last 2 bits */ pExtraData[3] |= (PacketLength & 0x1800) >> 11; @@ -256,33 +270,41 @@ static int writeDataADTS(WriterAVCallData_t *call) /* buffer fullness(0x7FF for VBR) continued over 6 first bits + 2 zeros for * number of raw data blocks */ pExtraData[6] = 0xFC; + //PesHeader[6] = 0x81; + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = headerSize + AAC_HEADER_LENGTH; iov[1].iov_base = call->data; iov[1].iov_len = call->len; + return call->WriteV(call->fd, iov, 2); } static int writeDataLATM(WriterAVCallData_t *call) { aac_printf(10, "\n"); + if (call == NULL) { aac_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { aac_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->private_data && 0 == strncmp("LATM", (const char *)call->private_data, call->private_size)) { return _writeData(call, 1); } + aac_printf(10, "AudioPts %lld\n", call->Pts); + if (!pLATMCtx) { pLATMCtx = malloc(sizeof(LATMContext)); @@ -290,11 +312,13 @@ static int writeDataLATM(WriterAVCallData_t *call) pLATMCtx->mod = 14; pLATMCtx->counter = 0; } + if (!pLATMCtx) { aac_err("parsing NULL pLATMCtx. ignoring...\n"); return 0; } + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; int ret = latmenc_decode_extradata(pLATMCtx, call->private_data, call->private_size); if (ret) @@ -310,14 +334,19 @@ static int writeDataLATM(WriterAVCallData_t *call) aac_err("latm_write_packet failed. ignoring...\n"); return 0; } + unsigned int HeaderLength = InsertPesHeader(PesHeader, pLATMCtx->len + 3, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); + struct iovec iov[3]; iov[0].iov_base = PesHeader; iov[0].iov_len = HeaderLength; + iov[1].iov_base = pLATMCtx->loas_header; iov[1].iov_len = 3; + iov[2].iov_base = pLATMCtx->buffer; iov[2].iov_len = pLATMCtx->len; + return call->WriteV(call->fd, iov, 3); } diff --git a/libeplayer3-arm/output/writer/mipsel/ac3.c b/libeplayer3-arm/output/writer/mipsel/ac3.c index 37ee989..12ade9a 100644 --- a/libeplayer3-arm/output/writer/mipsel/ac3.c +++ b/libeplayer3-arm/output/writer/mipsel/ac3.c @@ -98,34 +98,45 @@ static int reset() static int writeData(WriterAVCallData_t *call) { ac3_printf(10, "\n"); + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + if (call == NULL) { ac3_err("call data is NULL...\n"); return 0; } + ac3_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { ac3_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { ac3_err("file pointer < 0. ignoring ...\n"); return 0; } + struct iovec iov[3]; + iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); //+ sizeof(AC3_SYNC_HEADER) + //PesHeader[6] = 0x81; //PesHeader[7] = 0x80; //PesHeader[8] = 0x09; + //iov[1].iov_base = AC3_SYNC_HEADER; //iov[1].iov_len = sizeof(AC3_SYNC_HEADER); iov[1].iov_base = call->data; iov[1].iov_len = call->len; + ac3_printf(40, "PES HEADER LEN %d\n", iov[0].iov_len); + return call->WriteV(call->fd, iov, 2); } diff --git a/libeplayer3-arm/output/writer/mipsel/amr.c b/libeplayer3-arm/output/writer/mipsel/amr.c index d509ea5..98cc1a4 100644 --- a/libeplayer3-arm/output/writer/mipsel/amr.c +++ b/libeplayer3-arm/output/writer/mipsel/amr.c @@ -99,23 +99,29 @@ static int reset() static int writeData(WriterAVCallData_t *call) { unsigned char PesHeader[PES_MAX_HEADER_SIZE + 4 + 9]; + amr_printf(10, "\n"); + if (call == NULL) { amr_err("call data is NULL...\n"); return 0; } + amr_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { amr_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { amr_err("file pointer < 0. ignoring ...\n"); return 0; } + uint8_t hasCodecData = 1; if (NULL != call->private_data && call->private_size >= 17) { @@ -128,11 +134,13 @@ static int writeData(WriterAVCallData_t *call) payload_len += 9; } payload_len += 4; + uint32_t headerSize = InsertPesHeader(PesHeader, payload_len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); PesHeader[headerSize++] = (payload_len >> 24) & 0xff; PesHeader[headerSize++] = (payload_len >> 16) & 0xff; PesHeader[headerSize++] = (payload_len >> 8) & 0xff; PesHeader[headerSize++] = payload_len & 0xff; + if (hasCodecData) { uint8_t tmp[] = {0x45, 0x4d, 0x50, 0x20, 0x00, 0x00, 0x80, 0x00, 0x01}; @@ -140,12 +148,15 @@ static int writeData(WriterAVCallData_t *call) //memcpy(&PesHeader[headerSize], call->private_data + 8, 9); //memset(&PesHeader[headerSize], 0, 9); } + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = headerSize; iov[1].iov_base = call->data; iov[1].iov_len = call->len; + int len = call->WriteV(call->fd, iov, 2); + amr_printf(10, "amr_Write-< len=%d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/divx3.c b/libeplayer3-arm/output/writer/mipsel/divx3.c index de7ebab..d4de31f 100644 --- a/libeplayer3-arm/output/writer/mipsel/divx3.c +++ b/libeplayer3-arm/output/writer/mipsel/divx3.c @@ -118,25 +118,32 @@ static int writeData(WriterAVCallData_t *call) unsigned char PesHeader[PES_MAX_HEADER_SIZE + 4]; // unsigned char Version = 5; // unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE; + divx_printf(10, "\n"); + if (call == NULL) { divx_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { divx_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { divx_err("file pointer < 0. ignoring ...\n"); return 0; } + divx_printf(10, "AudioPts %lld\n", call->Pts); + struct iovec iov[8]; int ic = 0; + if (initialHeader) { initialHeader = 0; @@ -151,11 +158,14 @@ static int writeData(WriterAVCallData_t *call) data[2] = B_GET_BITS(height, 9, 2); data[3] = B_SET_BITS("height [1.0]", B_GET_BITS(height, 1, 0), 7, 6) | B_SET_BITS("'100000'", 0x20, 5, 0); + iov[ic].iov_base = brcm_divx311_sequence_header; iov[ic++].iov_len = sizeof(brcm_divx311_sequence_header); } + iov[ic].iov_base = PesHeader; uint32_t headerSize = 0; + if (memcmp(call->data, "\x00\x00\x01\xb6", 4)) { headerSize = InsertPesHeader(PesHeader, call->len + 4, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); @@ -167,10 +177,14 @@ static int writeData(WriterAVCallData_t *call) headerSize = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); } iov[ic++].iov_len = headerSize; + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; - int len = call->WriteV(call->fd, iov, ic); + + int len = call->WriteV(call->fd, iov, ic); + divx_printf(10, "xvid_Write < len=%d\n", len); + return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/dts.c b/libeplayer3-arm/output/writer/mipsel/dts.c index beb8e28..34548ba 100644 --- a/libeplayer3-arm/output/writer/mipsel/dts.c +++ b/libeplayer3-arm/output/writer/mipsel/dts.c @@ -103,25 +103,32 @@ static int32_t reset() static int writeData(WriterAVCallData_t *call) { uint8_t PesHeader[PES_AUDIO_HEADER_SIZE]; + dts_printf(10, "\n"); + if (call == NULL) { dts_err("call data is NULL...\n"); return 0; } + dts_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { dts_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { dts_err("file pointer < 0. ignoring ...\n"); return 0; } + uint8_t *Data = call->data; int32_t Size = call->len; + #ifdef CHECK_FOR_DTS_HD int32_t pos = 0; while ((pos + 4) <= Size) @@ -135,6 +142,7 @@ static int writeData(WriterAVCallData_t *call) ++pos; } #endif + // #define DO_BYTESWAP #ifdef DO_BYTESWAP /* 16-bit byte swap all data before injecting it */ @@ -145,11 +153,13 @@ static int writeData(WriterAVCallData_t *call) Data[i + 1] = Tmp; } #endif + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, Size, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); iov[1].iov_base = Data; iov[1].iov_len = Size; + int32_t len = call->WriteV(call->fd, iov, 2); dts_printf(10, "< len %d\n", len); return len; diff --git a/libeplayer3-arm/output/writer/mipsel/h263.c b/libeplayer3-arm/output/writer/mipsel/h263.c index 39c4ed2..1d8b0e5 100644 --- a/libeplayer3-arm/output/writer/mipsel/h263.c +++ b/libeplayer3-arm/output/writer/mipsel/h263.c @@ -95,37 +95,46 @@ static int writeData(WriterAVCallData_t *call) { uint8_t PesHeader[PES_MAX_HEADER_SIZE]; int32_t len = 0; + h263_printf(10, "\n"); + if (call == NULL) { h263_err("call data is NULL...\n"); return 0; } + h263_printf(10, "VideoPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { h263_err("NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { h263_err("file pointer < 0. ignoring ...\n"); return 0; } + int32_t HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); int32_t PrivateHeaderLength = InsertVideoPrivateDataHeader(&PesHeader[HeaderLength], call->len); int32_t PesLength = PesHeader[PES_LENGTH_BYTE_0] + (PesHeader[PES_LENGTH_BYTE_1] << 8) + PrivateHeaderLength; + PesHeader[PES_LENGTH_BYTE_0] = PesLength & 0xff; PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff; PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength; PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT; HeaderLength += PrivateHeaderLength; + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = HeaderLength; iov[1].iov_base = call->data; iov[1].iov_len = call->len; len = call->WriteV(call->fd, iov, 2); + h263_printf(10, "< len %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/h264.c b/libeplayer3-arm/output/writer/mipsel/h264.c index 4dbf2b6..8fe4be9 100644 --- a/libeplayer3-arm/output/writer/mipsel/h264.c +++ b/libeplayer3-arm/output/writer/mipsel/h264.c @@ -103,34 +103,45 @@ static int sps_pps_in_stream = 0; static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, uint8_t *pData, uint32_t dataSize) { uint8_t *aExtraData = *ppExtraData; + if (aExtraData[0] != 1 || !pData) { // Not AVCC or nothing to update with. return -1; } + int32_t nalsize = (aExtraData[4] & 3) + 1; + uint8_t sps[256]; uint8_t spsIdx = 0; + uint8_t numSps = 0; + uint8_t pps[256]; uint8_t ppsIdx = 0; + uint8_t numPps = 0; + if (nalsize != 4) { return -1; } + // Find SPS and PPS NALUs in AVCC data uint8_t *d = pData; while (d + 4 < pData + dataSize) { uint32_t nalLen = ReadUint32(d); + uint8_t nalType = d[4] & 0x1f; if (nalType == 7) { /* SPS */ + // 16 bits size sps[spsIdx++] = (uint8_t)(0xFF & (nalLen >> 8)); sps[spsIdx++] = (uint8_t)(0xFF & nalLen); + if (spsIdx + nalLen >= sizeof(sps)) { h264_err("SPS no free space to copy...\n"); @@ -138,15 +149,19 @@ static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, } memcpy(&(sps[spsIdx]), d + 4, nalLen); spsIdx += nalLen; + numSps += 1; + h264_printf(10, "SPS len[%u]...\n", nalLen); } else if (nalType == 8) { /* PPS */ + // 16 bits size pps[ppsIdx++] = (uint8_t)(0xFF & (nalLen >> 8)); pps[ppsIdx++] = (uint8_t)(0xFF & nalLen); + if (ppsIdx + nalLen >= sizeof(sps)) { h264_err("PPS not free space to copy...\n"); @@ -154,7 +169,9 @@ static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, } memcpy(&(pps[ppsIdx]), d + 4, nalLen); ppsIdx += nalLen; + numPps += 1; + h264_printf(10, "PPS len[%u]...\n", nalLen); } d += 4 + nalLen; @@ -167,18 +184,21 @@ static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, aExtraData[idx++] = sps[4]; // profile compat aExtraData[idx++] = sps[5]; // level aExtraData[idx++] = 0xff; // nal size - 1 + aExtraData[idx++] = 0xe0 | numSps; if (numSps) { memcpy(&(aExtraData[idx]), sps, spsIdx); idx += spsIdx; } + aExtraData[idx++] = numPps; if (numPps) { memcpy(&(aExtraData[idx]), pps, ppsIdx); idx += ppsIdx; } + h264_printf(10, "aExtraData len[%u]...\n", idx); *pExtraDataSize = idx; return 0; @@ -192,6 +212,7 @@ static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigne { unsigned char tmp[2048]; unsigned int tmp_len = 0; + unsigned int cd_pos = 0; h264_printf(10, "H264 have codec data..!\n"); if (cd_len > 7 && data[0] == 1) @@ -238,9 +259,11 @@ static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigne tmp_len += 4; memcpy(tmp + tmp_len, data + cd_pos, len); tmp_len += len; + CodecData = malloc(tmp_len); memcpy(CodecData, tmp, tmp_len); CodecDataLen = tmp_len; + *NalLength = (data[4] & 0x03) + 1; ret = 0; } @@ -297,28 +320,34 @@ static int writeData(WriterAVCallData_t *call) int ic = 0; struct iovec iov[IOVEC_SIZE]; h264_printf(20, "\n"); + if (call == NULL) { h264_err("call data is NULL...\n"); return 0; } + TimeDelta = call->FrameRate; TimeScale = call->FrameScale; /* avoid compiler warnings */ if (TimeDelta) {} if (TimeScale) {} VideoPts = call->Pts; + h264_printf(20, "VideoPts %lld - %d %d\n", call->Pts, TimeDelta, TimeScale); + if ((call->data == NULL) || (call->len <= 0)) { h264_err("NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { h264_err("file pointer < 0. ignoring ...\n"); return 0; } + /* AnnexA */ if (!avc3 && ((1 < call->private_size && 0 == call->private_data[0]) || ((call->len > 3) && ((call->data[0] == 0x00 && call->data[1] == 0x00 && call->data[2] == 0x00 && call->data[3] == 0x01) || @@ -329,6 +358,7 @@ static int writeData(WriterAVCallData_t *call) uint32_t PacketLength = 0; uint32_t FakeStartCode = (call->Version << 8) | PES_VERSION_FAKE_START_CODE; iov[ic++].iov_base = PesHeader; + while (InsertPrivData && i < 36 && (call->len - i) > 5) { if ((call->data[i] == 0x00 && call->data[i + 1] == 0x00 && call->data[i + 2] == 0x00 && call->data[i + 3] == 0x01 && (call->data[i + 4] == 0x67 || call->data[i + 4] == 0x68))) @@ -338,6 +368,7 @@ static int writeData(WriterAVCallData_t *call) } i += 1; } + if (InsertPrivData && call->private_size > 0 /*&& initialHeader*/) // some rtsp streams can update codec data at runtime { initialHeader = 0; @@ -345,10 +376,13 @@ static int writeData(WriterAVCallData_t *call) iov[ic++].iov_len = call->private_size; PacketLength += call->private_size; } + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; PacketLength += call->len; + iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, FakeStartCode); + return call->WriteV(call->fd, iov, ic); } else if (!call->private_data || call->private_size < 7 || 1 != call->private_data[0]) @@ -356,9 +390,12 @@ static int writeData(WriterAVCallData_t *call) h264_err("No valid private data available! [%d]\n", (int)call->private_size); return 0; } + uint32_t PacketLength = 0; + ic = 0; iov[ic++].iov_base = PesHeader; + //if (initialHeader) { if (CodecData) @@ -366,19 +403,23 @@ static int writeData(WriterAVCallData_t *call) free(CodecData); CodecData = NULL; } + uint8_t *private_data = call->private_data; uint32_t private_size = call->private_size; + if (PreparCodecData(private_data, private_size, &NalLengthBytes)) { UpdateExtraData(&private_data, &private_size, call->data, call->len); PreparCodecData(private_data, private_size, &NalLengthBytes); } + if (private_data != call->private_data) { avc3 = 1; free(private_data); private_data = NULL; } + if (CodecData != NULL) { iov[ic].iov_base = CodecData; @@ -387,6 +428,7 @@ static int writeData(WriterAVCallData_t *call) initialHeader = 0; } } + if (CodecData != NULL) { uint32_t pos = 0; @@ -397,6 +439,7 @@ static int writeData(WriterAVCallData_t *call) h264_err(">> Drop data due to ic overflow\n"); break; } + uint32_t pack_len = 0; uint32_t i = 0; for (i = 0; i < NalLengthBytes; i++, pos++) @@ -404,21 +447,28 @@ static int writeData(WriterAVCallData_t *call) pack_len <<= 8; pack_len += call->data[pos]; } + if ((pos + pack_len) > call->len) { pack_len = call->len - pos; } + iov[ic].iov_base = Head; iov[ic++].iov_len = sizeof(Head); PacketLength += sizeof(Head); + iov[ic].iov_base = call->data + pos; iov[ic++].iov_len = pack_len; PacketLength += pack_len; + pos += pack_len; + } while ((pos + NalLengthBytes) < call->len); + h264_printf(10, "<<<< PacketLength [%d]\n", PacketLength); iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, 0); + len = call->WriteV(call->fd, iov, ic); PacketLength += iov[0].iov_len; if (PacketLength != len) @@ -426,6 +476,7 @@ static int writeData(WriterAVCallData_t *call) h264_err("<<<< not all data have been written [%d/%d]\n", len, PacketLength); } } + h264_printf(10, "< len %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/h265.c b/libeplayer3-arm/output/writer/mipsel/h265.c index ad59853..1e61411 100644 --- a/libeplayer3-arm/output/writer/mipsel/h265.c +++ b/libeplayer3-arm/output/writer/mipsel/h265.c @@ -105,7 +105,9 @@ static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigne { unsigned char tmp[2048]; unsigned int tmp_len = 0; + h264_printf(10, "H265 have codec data..!"); + if (cd_len > 3 && (data[0] || data[1] || data[2] > 1)) { if (cd_len > 22) @@ -115,6 +117,7 @@ static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigne { h264_printf(10, "Unsupported extra data version %d, decoding may fail", (int)data[0]); } + *NalLength = (data[21] & 3) + 1; int num_param_sets = data[22]; uint32_t pos = 23; @@ -150,6 +153,7 @@ static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigne pos += nal_size; } } + CodecData = malloc(tmp_len); memcpy(CodecData, tmp, tmp_len); CodecDataLen = tmp_len; @@ -160,6 +164,7 @@ static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigne { *NalLength = 0; } + return ret; } @@ -179,33 +184,40 @@ static int writeData(WriterAVCallData_t *call) int ic = 0; struct iovec iov[IOVEC_SIZE]; h264_printf(20, "\n"); + if (call == NULL) { h264_err("call data is NULL...\n"); return 0; } + TimeDelta = call->FrameRate; TimeScale = call->FrameScale; /* avoid compiler warnings */ if (TimeDelta) {} if (TimeScale) {} VideoPts = call->Pts; + h264_printf(20, "VideoPts %lld - %d %d\n", call->Pts, TimeDelta, TimeScale); + if ((call->data == NULL) || (call->len <= 0)) { h264_err("NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { h264_err("file pointer < 0. ignoring ...\n"); return 0; } + if (call->InfoFlags & 0x1) // TS container { h264_printf(10, "H265 simple inject method!\n"); uint32_t PacketLength = 0; uint32_t FakeStartCode = (call->Version << 8) | PES_VERSION_FAKE_START_CODE; + iov[ic++].iov_base = PesHeader; initialHeader = 0; if (initialHeader) @@ -215,17 +227,24 @@ static int writeData(WriterAVCallData_t *call) iov[ic++].iov_len = call->private_size; PacketLength += call->private_size; } + iov[ic].iov_base = ""; iov[ic++].iov_len = 1; + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; PacketLength += call->len; + iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, FakeStartCode); + return call->WriteV(call->fd, iov, ic); } + uint32_t PacketLength = 0; + ic = 0; iov[ic++].iov_base = PesHeader; + if (initialHeader) { if (CodecData) @@ -233,9 +252,12 @@ static int writeData(WriterAVCallData_t *call) free(CodecData); CodecData = NULL; } + uint8_t *private_data = call->private_data; uint32_t private_size = call->private_size; + PreparCodecData(private_data, private_size, &NalLengthBytes); + if (CodecData != NULL) { iov[ic].iov_base = CodecData; @@ -244,6 +266,7 @@ static int writeData(WriterAVCallData_t *call) initialHeader = 0; } } + if (CodecData != NULL) { uint32_t pos = 0; @@ -254,6 +277,7 @@ static int writeData(WriterAVCallData_t *call) h264_err(">> Drop data due to ic overflow\n"); break; } + uint32_t pack_len = 0; uint32_t i = 0; for (i = 0; i < NalLengthBytes; i++, pos++) @@ -261,21 +285,28 @@ static int writeData(WriterAVCallData_t *call) pack_len <<= 8; pack_len += call->data[pos]; } + if ((pos + pack_len) > call->len) { pack_len = call->len - pos; } + iov[ic].iov_base = Head; iov[ic++].iov_len = sizeof(Head); PacketLength += sizeof(Head); + iov[ic].iov_base = call->data + pos; iov[ic++].iov_len = pack_len; PacketLength += pack_len; + pos += pack_len; + } while ((pos + NalLengthBytes) < call->len); + h264_printf(10, "<<<< PacketLength [%d]\n", PacketLength); iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, 0); + len = call->WriteV(call->fd, iov, ic); PacketLength += iov[0].iov_len; if (PacketLength != len) @@ -283,6 +314,7 @@ static int writeData(WriterAVCallData_t *call) h264_err("<<<< not all data have been written [%d/%d]\n", len, PacketLength); } } + h264_printf(10, "< len %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/lpcm.c b/libeplayer3-arm/output/writer/mipsel/lpcm.c index f03fc5d..cf099a2 100644 --- a/libeplayer3-arm/output/writer/mipsel/lpcm.c +++ b/libeplayer3-arm/output/writer/mipsel/lpcm.c @@ -59,7 +59,6 @@ /* ***************************** */ //#define SAM_WITH_DEBUG - #ifdef SAM_WITH_DEBUG #define LPCM_DEBUG #else @@ -135,23 +134,29 @@ static int32_t reset() static int writeData(WriterAVCallData_t *call) { lpcm_printf(10, "\n"); + if (!call) { lpcm_err("call data is NULL...\n"); return 0; } + lpcm_printf(10, "AudioPts %lld\n", call->Pts); + if (!call->data || (call->len <= 0)) { lpcm_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { lpcm_err("file pointer < 0. ignoring ...\n"); return 0; } + pcmPrivateData_t *pcmPrivateData = (pcmPrivateData_t *)call->private_data; + int32_t i_rate = (int32_t)pcmPrivateData->sample_rate; int32_t i_channels = (int32_t)pcmPrivateData->channels; int32_t i_nb_samples = call->len / (i_channels * 2); @@ -161,6 +166,7 @@ static int writeData(WriterAVCallData_t *call) lpcm_err("Error DVD LPCM supports a maximum of eight channels i_channels[%d]\n", i_channels); return 0; } + if (pcmPrivateData->bResampling || NULL == p_buffer) { lpcm_printf(1, "i_rate: [%d]\n", i_rate); @@ -183,6 +189,7 @@ static int writeData(WriterAVCallData_t *call) lpcm_err("Error DVD LPCM sample_rate not supported [%d]\n", i_rate); return 0; } + /* In DVD LCPM, a frame is always 150 PTS ticks. */ i_frame_samples = i_rate * 150 / 90000; i_frame_size = i_frame_samples * i_channels * 2 + LLPCM_VOB_HEADER_LEN; @@ -191,6 +198,7 @@ static int writeData(WriterAVCallData_t *call) free(p_buffer); } p_buffer = malloc(i_frame_samples * i_channels * 16); + if (NULL != p_frame_buffer) { free(p_frame_buffer); @@ -200,9 +208,11 @@ static int writeData(WriterAVCallData_t *call) i_frame_num = 0; i_bitspersample = 16; } + const int i_num_frames = (i_buffer_used + i_nb_samples) / i_frame_samples; const int i_leftover_samples = (i_buffer_used + i_nb_samples) % i_frame_samples; const int i_start_offset = -i_buffer_used; + int32_t i_bytes_consumed = 0; int32_t i = 0; for (i = 0; i < i_num_frames; ++i) @@ -214,9 +224,11 @@ static int writeData(WriterAVCallData_t *call) frame[3] = (i_frame_num + i) & 0x1f; /* no emphasis, no mute */ frame[4] = (i_freq_code << 4) | (i_channels - 1); frame[5] = 0x80; /* neutral dynamic range */ + const int i_consume_samples = i_frame_samples - i_buffer_used; const int i_kept_bytes = i_buffer_used * i_channels * 2; const int i_consume_bytes = i_consume_samples * i_channels * 2; + #ifdef WORDS_BIGENDIAN memcpy(frame + 6, p_buffer, i_kept_bytes); memcpy(frame + 6 + i_kept_bytes, call->data + i_bytes_consumed, i_consume_bytes); @@ -224,15 +236,20 @@ static int writeData(WriterAVCallData_t *call) swab(p_buffer, frame + 6, i_kept_bytes); swab(call->data + i_bytes_consumed, frame + 6 + i_kept_bytes, i_consume_bytes); #endif + i_frame_num++; i_buffer_used = 0; i_bytes_consumed += i_consume_bytes; + /* We need to find i_length by means of next_pts due to possible roundoff errors. */ uint64_t this_pts = call->Pts + (i * i_frame_samples + i_start_offset) * 90000 / i_rate; + uint32_t pes_header_size = 0; pes_header_size = InsertPesHeader(PesHeader, i_frame_size + 1, MPEG_AUDIO_PES_START_CODE, this_pts, 0); + PesHeader[pes_header_size] = 0xa0; pes_header_size += 1; + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = pes_header_size; @@ -240,8 +257,10 @@ static int writeData(WriterAVCallData_t *call) iov[1].iov_len = i_frame_size; i_ret_size += call->WriteV(call->fd, iov, 2); } + memcpy(p_buffer, call->data + i_bytes_consumed, i_leftover_samples * i_channels * 2); i_buffer_used = i_leftover_samples; + return i_ret_size; } diff --git a/libeplayer3-arm/output/writer/mipsel/mp3.c b/libeplayer3-arm/output/writer/mipsel/mp3.c index 3271f98..9eb9f5c 100644 --- a/libeplayer3-arm/output/writer/mipsel/mp3.c +++ b/libeplayer3-arm/output/writer/mipsel/mp3.c @@ -94,24 +94,31 @@ static int reset() static int writeData(WriterAVCallData_t *call) { unsigned char PesHeader[PES_MAX_HEADER_SIZE + 22]; + mp3_printf(10, "\n"); + if (call == NULL) { mp3_err("call data is NULL...\n"); return 0; } + mp3_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { mp3_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { mp3_err("file pointer < 0. ignoring ...\n"); return 0; } + call->private_size = 0; + uint32_t headerSize = InsertPesHeader(PesHeader, call->len + call->private_size, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); if (call->private_size > 0) { @@ -123,7 +130,9 @@ static int writeData(WriterAVCallData_t *call) iov[0].iov_len = headerSize; iov[1].iov_base = call->data; iov[1].iov_len = call->len; + int len = call->WriteV(call->fd, iov, 2); + mp3_printf(10, "mp3_Write-< len=%d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/mpeg2.c b/libeplayer3-arm/output/writer/mipsel/mpeg2.c index 2e53f70..aecc701 100644 --- a/libeplayer3-arm/output/writer/mipsel/mpeg2.c +++ b/libeplayer3-arm/output/writer/mipsel/mpeg2.c @@ -95,36 +95,47 @@ static int reset() static int writeData(WriterAVCallData_t *call) { unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + int len = 0; unsigned int Position = 0; + mpeg2_printf(10, "\n"); + if (call == NULL) { mpeg2_err("call data is NULL...\n"); return 0; } + mpeg2_printf(10, "VideoPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { mpeg2_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { mpeg2_err("file pointer < 0. ignoring ...\n"); return 0; } + while (Position < call->len) { int PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ? (call->len - Position) : MAX_PES_PACKET_SIZE; + int Remaining = call->len - Position - PacketLength; + mpeg2_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position); + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, 0xe0, call->Pts, 0); iov[1].iov_base = call->data + Position; iov[1].iov_len = PacketLength; + ssize_t l = call->WriteV(call->fd, iov, 2); if (l < 0) { @@ -132,9 +143,11 @@ static int writeData(WriterAVCallData_t *call) break; } len += l; + Position += PacketLength; call->Pts = INVALID_PTS_VALUE; } + mpeg2_printf(10, "< len %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/mpeg4.c b/libeplayer3-arm/output/writer/mipsel/mpeg4.c index 23cb154..0086992 100644 --- a/libeplayer3-arm/output/writer/mipsel/mpeg4.c +++ b/libeplayer3-arm/output/writer/mipsel/mpeg4.c @@ -103,32 +103,40 @@ static int reset() static int writeData(WriterAVCallData_t *call) { unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + mpeg4_printf(10, "\n"); + if (call == NULL) { mpeg4_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { mpeg4_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { mpeg4_err("file pointer < 0. ignoring ...\n"); return 0; } + mpeg4_printf(10, "VideoPts %lld\n", call->Pts); + unsigned int PacketLength = call->len; if (initialHeader && call->private_size && call->private_data != NULL) { PacketLength += call->private_size; } + struct iovec iov[3]; int ic = 0; iov[ic].iov_base = PesHeader; iov[ic++].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); + if (initialHeader && call->private_size && call->private_data != NULL) { initialHeader = 0; @@ -137,8 +145,11 @@ static int writeData(WriterAVCallData_t *call) } iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; + int len = call->WriteV(call->fd, iov, ic); + mpeg4_printf(10, "xvid_Write < len=%d\n", len); + return len; } diff --git a/libeplayer3-arm/output/writer/mipsel/pcm.c b/libeplayer3-arm/output/writer/mipsel/pcm.c index 8246100..f50ab64 100644 --- a/libeplayer3-arm/output/writer/mipsel/pcm.c +++ b/libeplayer3-arm/output/writer/mipsel/pcm.c @@ -56,8 +56,6 @@ /* Makros/Constants */ /* ***************************** */ -//#define SAM_WITH_DEBUG - #ifdef SAM_WITH_DEBUG #define PCM_DEBUG #else @@ -113,26 +111,32 @@ static int32_t reset() static int writeData(WriterAVCallData_t *call) { pcm_printf(10, "\n"); + if (!call) { pcm_err("call data is NULL...\n"); return 0; } + pcm_printf(10, "AudioPts %lld\n", call->Pts); + if (!call->data || (call->len <= 0)) { pcm_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { pcm_err("file pointer < 0. ignoring ...\n"); return 0; } + static uint8_t PesHeader[PES_MAX_HEADER_SIZE + 22]; pcmPrivateData_t *pcmPrivateData = (pcmPrivateData_t *)call->private_data; uint8_t *buffer = call->data; uint32_t size = call->len; + if (pcmPrivateData->bResampling || NULL == fixed_buffer) { if (0) @@ -143,14 +147,18 @@ static int writeData(WriterAVCallData_t *call) printf("ioctl %d", ioctl(call->fd, AUDIO_PLAY)); printf("ioctl %d", ioctl(call->fd, AUDIO_CONTINUE)); } + int32_t format = 0x01; + int32_t width = 0; int32_t depth = 0; int32_t rate = (uint64_t)pcmPrivateData->sample_rate; int32_t channels = (uint8_t) pcmPrivateData->channels; int32_t block_align = 0; int32_t byterate = 0; + uint32_t codecID = (uint32_t)pcmPrivateData->ffmpeg_codec_id; + //uint8_t dataPrecision = 0; uint8_t LE = 0; switch (codecID) @@ -183,7 +191,9 @@ static int writeData(WriterAVCallData_t *call) default: break; } + uint8_t *data = codec_data; + byterate = channels * rate * width / 8; block_align = channels * width / 8; memset(data, 0, sizeof(codec_data)); @@ -209,10 +219,12 @@ static int writeData(WriterAVCallData_t *call) /* word size */ *(data++) = depth & 0xff; *(data++) = (depth >> 8) & 0xff; + uint32_t nfixed_buffersize = rate * 30 / 1000; nfixed_buffersize *= channels * depth / 8; fixed_buffertimestamp = call->Pts; fixed_bufferduration = 90000 * nfixed_buffersize / byterate; + if (fixed_buffersize != nfixed_buffersize || NULL == fixed_buffer) { fixed_buffersize = nfixed_buffersize; @@ -227,6 +239,7 @@ static int writeData(WriterAVCallData_t *call) if (LE) {} //printf("PCM fixed_buffersize [%u] [%s]\n", fixed_buffersize, LE ? "LE":"BE"); } + while (size > 0) { uint32_t cpSize = (fixed_buffersize - fixed_bufferfilled); @@ -236,10 +249,12 @@ static int writeData(WriterAVCallData_t *call) fixed_bufferfilled += size; return size; } + memcpy(fixed_buffer + fixed_bufferfilled, buffer, cpSize); fixed_bufferfilled = 0; buffer += cpSize; size -= cpSize; + uint32_t addHeaderSize = 0; if (IsDreambox()) { @@ -253,13 +268,17 @@ static int writeData(WriterAVCallData_t *call) PesHeader[headerSize++] = 0x4D; // M PesHeader[headerSize++] = 0x41; // A } + PesHeader[headerSize++] = (fixed_buffersize >> 24) & 0xff; PesHeader[headerSize++] = (fixed_buffersize >> 16) & 0xff; PesHeader[headerSize++] = (fixed_buffersize >> 8) & 0xff; PesHeader[headerSize++] = fixed_buffersize & 0xff; + memcpy(PesHeader + headerSize, codec_data, sizeof(codec_data)); headerSize += sizeof(codec_data); + PesHeader[6] |= 1; + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = headerSize; @@ -267,10 +286,13 @@ static int writeData(WriterAVCallData_t *call) iov[1].iov_len = fixed_buffersize; call->WriteV(call->fd, iov, 2); fixed_buffertimestamp += fixed_bufferduration; - int g_fd_dump = open("/hdd/lpcm/ffmpeg.pes", O_CREAT | O_RDWR | O_APPEND, S_IRUSR | S_IWUSR); + + int g_fd_dump = open("/hdd/lpcm/ffmpeg.pes", O_CREAT | + O_RDWR | O_APPEND, S_IRUSR | S_IWUSR); call->WriteV(g_fd_dump, iov, 2); close(g_fd_dump); } + return size; } diff --git a/libeplayer3-arm/output/writer/mipsel/vc1.c b/libeplayer3-arm/output/writer/mipsel/vc1.c index d291e2a..0cdb63b 100644 --- a/libeplayer3-arm/output/writer/mipsel/vc1.c +++ b/libeplayer3-arm/output/writer/mipsel/vc1.c @@ -79,6 +79,7 @@ if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); #define vc1_err(fmt, x...) #endif + /* ***************************** */ /* Types */ /* ***************************** */ @@ -110,28 +111,35 @@ static int reset() static int writeData(WriterAVCallData_t *call) { //int len = 0; + vc1_printf(10, "\n"); + if (call == NULL) { vc1_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { vc1_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { vc1_err("file pointer < 0. ignoring ...\n"); return 0; } + vc1_printf(10, "VideoPts %lld\n", call->Pts); vc1_printf(10, "Got Private Size %d\n", call->private_size); + unsigned char PesHeader[PES_MAX_HEADER_SIZE + sizeof(Vc1FrameStartCode)]; int32_t ic = 0; struct iovec iov[5]; unsigned int PacketLength = 0; + iov[ic++].iov_base = PesHeader; if (initialHeader) { @@ -152,6 +160,7 @@ static int writeData(WriterAVCallData_t *call) PacketLength += videocodecdata.length; } } + uint8_t needFrameStartCode = 0; if (sizeof(Vc1FrameStartCode) >= call->len || memcmp(call->data, Vc1FrameStartCode, sizeof(Vc1FrameStartCode)) != 0) @@ -159,22 +168,28 @@ static int writeData(WriterAVCallData_t *call) needFrameStartCode = 1; PacketLength += sizeof(Vc1FrameStartCode); } + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; PacketLength += call->len; + iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); + /* some mipsel receiver(s) like et4x00 needs to have Copy(0)/Original(1) flag set to Original */ PesHeader[6] |= 1; + if (needFrameStartCode) { memcpy(PesHeader + iov[0].iov_len, Vc1FrameStartCode, sizeof(Vc1FrameStartCode)); iov[0].iov_len += sizeof(Vc1FrameStartCode); } + if (videocodecdata.data) { free(videocodecdata.data); videocodecdata.data = NULL; } + return call->WriteV(call->fd, iov, ic); } diff --git a/libeplayer3-arm/output/writer/mipsel/vp.c b/libeplayer3-arm/output/writer/mipsel/vp.c index 0c61c8c..a9f75aa 100644 --- a/libeplayer3-arm/output/writer/mipsel/vp.c +++ b/libeplayer3-arm/output/writer/mipsel/vp.c @@ -54,7 +54,6 @@ /* ***************************** */ //#define SAM_WITH_DEBUG - #ifdef SAM_WITH_DEBUG #define VP_DEBUG #else @@ -77,6 +76,7 @@ if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); #define vp_err(fmt, x...) #endif + /* ***************************** */ /* Types */ /* ***************************** */ @@ -101,25 +101,31 @@ static int reset() static int writeData(WriterAVCallData_t *call, int is_vp6) { vp_printf(10, "\n"); + if (call == NULL) { vp_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { vp_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { vp_err("file pointer < 0. ignoring ...\n"); return 0; } + vp_printf(10, "VideoPts %lld\n", call->Pts); vp_printf(10, "Got Private Size %d\n", call->private_size); + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; struct iovec iov[2]; + iov[0].iov_base = PesHeader; uint32_t pes_header_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); uint32_t len = call->len + 4 + 6; @@ -138,6 +144,7 @@ static int writeData(WriterAVCallData_t *call, int is_vp6) iov[0].iov_len = pes_header_len; iov[1].iov_base = call->data; iov[1].iov_len = call->len; + return call->WriteV(call->fd, iov, 2); } diff --git a/libeplayer3-arm/output/writer/mipsel/wma.c b/libeplayer3-arm/output/writer/mipsel/wma.c index cea0459..15d6b2d 100644 --- a/libeplayer3-arm/output/writer/mipsel/wma.c +++ b/libeplayer3-arm/output/writer/mipsel/wma.c @@ -53,8 +53,6 @@ /* Makros/Constants */ /* ***************************** */ -//#define SAM_WITH_DEBUG - #ifdef SAM_WITH_DEBUG #define WMA_DEBUG #else @@ -106,28 +104,36 @@ static int reset() static int writeData(WriterAVCallData_t *call) { //int len = 0; + wma_printf(10, "\n"); + if (call == NULL) { wma_err("call data is NULL...\n"); return 0; } + wma_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { wma_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { wma_err("file pointer < 0. ignoring ...\n"); return 0; } + uint32_t packetLength = 4 + call->private_size + call->len; + if (IsDreambox()) { packetLength += 4; } + if ((packetLength + PES_MAX_HEADER_SIZE) > MaxPesHeader) { if (PesHeader) @@ -137,6 +143,7 @@ static int writeData(WriterAVCallData_t *call) MaxPesHeader = packetLength + PES_MAX_HEADER_SIZE; PesHeader = malloc(MaxPesHeader); } + uint32_t headerSize = InsertPesHeader(PesHeader, packetLength, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); if (IsDreambox()) { @@ -145,14 +152,18 @@ static int writeData(WriterAVCallData_t *call) PesHeader[headerSize++] = 0x4D; // M PesHeader[headerSize++] = 0x41; // A } + size_t payload_len = call->len; PesHeader[headerSize++] = (payload_len >> 24) & 0xff; PesHeader[headerSize++] = (payload_len >> 16) & 0xff; PesHeader[headerSize++] = (payload_len >> 8) & 0xff; PesHeader[headerSize++] = payload_len & 0xff; + memcpy(PesHeader + headerSize, call->private_data, call->private_size); headerSize += call->private_size; + PesHeader[6] |= 1; + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = headerSize; diff --git a/libeplayer3-arm/output/writer/mipsel/wmv.c b/libeplayer3-arm/output/writer/mipsel/wmv.c index 225697b..13934c7 100644 --- a/libeplayer3-arm/output/writer/mipsel/wmv.c +++ b/libeplayer3-arm/output/writer/mipsel/wmv.c @@ -108,27 +108,33 @@ static int reset() static int writeData(WriterAVCallData_t *call) { wmv_printf(10, "\n"); + if (call == NULL) { wmv_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { wmv_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { wmv_err("file pointer < 0. ignoring ...\n"); return 0; } + wmv_printf(10, "VideoPts %lld\n", call->Pts); wmv_printf(10, "Got Private Size %d\n", call->private_size); + unsigned char PesHeader[PES_MAX_HEADER_SIZE + sizeof(Vc1FrameStartCode)]; int32_t ic = 0; struct iovec iov[5]; unsigned int PacketLength = 0; + iov[ic++].iov_base = PesHeader; if (initialHeader) { @@ -138,8 +144,10 @@ static int writeData(WriterAVCallData_t *call) free(videocodecdata.data); videocodecdata.data = NULL; } + unsigned int codec_size = call->private_size; if (codec_size > 4) codec_size = 4; + videocodecdata.length = 33; uint8_t *data = videocodecdata.data = malloc(videocodecdata.length); memset(videocodecdata.data, 0, videocodecdata.length); @@ -158,6 +166,7 @@ static int writeData(WriterAVCallData_t *call) PacketLength += videocodecdata.length; } } + uint8_t needFrameStartCode = 0; if (sizeof(Vc1FrameStartCode) >= call->len || memcmp(call->data, Vc1FrameStartCode, sizeof(Vc1FrameStartCode)) != 0) @@ -165,22 +174,28 @@ static int writeData(WriterAVCallData_t *call) needFrameStartCode = 1; PacketLength += sizeof(Vc1FrameStartCode); } + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; PacketLength += call->len; + iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); + /* some mipsel receiver(s) like et4x00 needs to have Copy(0)/Original(1) flag set to Original */ PesHeader[6] |= 1; + if (needFrameStartCode) { memcpy(PesHeader + iov[0].iov_len, Vc1FrameStartCode, sizeof(Vc1FrameStartCode)); iov[0].iov_len += sizeof(Vc1FrameStartCode); } + if (videocodecdata.data) { free(videocodecdata.data); videocodecdata.data = NULL; } + return call->WriteV(call->fd, iov, ic); } diff --git a/libeplayer3-arm/output/writer/mipsel/writer.c b/libeplayer3-arm/output/writer/mipsel/writer.c index 829e4db..209c75c 100644 --- a/libeplayer3-arm/output/writer/mipsel/writer.c +++ b/libeplayer3-arm/output/writer/mipsel/writer.c @@ -111,7 +111,7 @@ ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, const void *buf, { fd_set rfds; fd_set wfds; - + ssize_t ret; int retval = -1; int maxFd = pipefd > fd ? pipefd : fd; @@ -125,36 +125,36 @@ ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, const void *buf, FD_SET(pipefd, &rfds); FD_SET(fd, &wfds); - /* When we PAUSE LINUX DVB outputs buffers then audio/video buffers - * will be filled to full unfortunately, in such case after resume + /* When we PAUSE LINUX DVB outputs buffers then audio/video buffers + * will be filled to full unfortunately, in such case after resume * select never return with fd set - bug in DVB drivers? * So, there will be to workarounds: * 1. write to pipe pipe at resume to exit select immediately - * 2. even if fd is not set exit from select after 0,1s + * 2. even if fd is not set exit from select after 0,1s * (it seems that second workaround is not needed) */ //tv.tv_sec = 0; //tv.tv_usec = 100000; // 100ms - + retval = select(maxFd + 1, &rfds, &wfds, NULL, NULL); //&tv); if (retval < 0) { break; } - + //if (retval == 0) //{ // //printf("RETURN FROM SELECT DUE TO TIMEOUT TIMEOUT\n"); // continue; //} - + if(FD_ISSET(pipefd, &rfds)) { FlusPipe(pipefd); //printf("RETURN FROM SELECT DUE TO pipefd SET\n"); continue; } - + if(FD_ISSET(fd, &wfds)) { ret = write(fd, buf, size); @@ -173,7 +173,7 @@ ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, const void *buf, { break; } - + return ret; } else if (ret == 0) @@ -186,7 +186,7 @@ ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, const void *buf, FlusPipe(pipefd); continue; } - + size -= ret; buf += ret; } @@ -219,12 +219,15 @@ ssize_t write_with_retry(int fd, const void *buf, size_t size) break; } } + if (ret < 0) { return ret; } + size -= ret; buf += ret; + if (size > 0) { if (usleep(1000)) @@ -255,6 +258,7 @@ ssize_t writev_with_retry(int fd, const struct iovec *iov, size_t ic) Writer_t *getWriter(char *encoding) { int i; + for (i = 0; AvailableWriter[i] != NULL; i++) { if (strcmp(AvailableWriter[i]->caps->textEncoding, encoding) == 0) @@ -263,13 +267,16 @@ Writer_t *getWriter(char *encoding) return AvailableWriter[i]; } } + writer_printf(1, "%s: no writer found for \"%s\"\n", __func__, encoding); + return NULL; } Writer_t *getDefaultVideoWriter() { int i; + for (i = 0; AvailableWriter[i] != NULL; i++) { if (strcmp(AvailableWriter[i]->caps->textEncoding, "V_MPEG2") == 0) @@ -278,13 +285,16 @@ Writer_t *getDefaultVideoWriter() return AvailableWriter[i]; } } + writer_printf(1, "%s: no writer found\n", __func__); + return NULL; } Writer_t *getDefaultAudioWriter() { int i; + for (i = 0; AvailableWriter[i] != NULL; i++) { if (strcmp(AvailableWriter[i]->caps->textEncoding, "A_MP3") == 0) @@ -293,6 +303,8 @@ Writer_t *getDefaultAudioWriter() return AvailableWriter[i]; } } + writer_printf(1, "%s: no writer found\n", __func__); + return NULL; } diff --git a/libeplayer3-arm/output/writer/sh4/aac.c b/libeplayer3-arm/output/writer/sh4/aac.c index e70336c..28b06b8 100644 --- a/libeplayer3-arm/output/writer/sh4/aac.c +++ b/libeplayer3-arm/output/writer/sh4/aac.c @@ -43,6 +43,7 @@ #include #include "ffmpeg/latmenc.h" + #include "common.h" #include "output.h" #include "debug.h" @@ -157,17 +158,21 @@ static int reset() static int _writeData(void *_call, int type) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + aac_printf(10, "\n _writeData type[%d]\n", type); + if (call == NULL) { aac_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len < 8)) { aac_err("parsing Data with missing AAC header. ignoring...\n"); return 0; } + /* simple validation */ if (0 == type) // check ADTS header { @@ -194,9 +199,13 @@ static int _writeData(void *_call, int type) return 0; } } + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + aac_printf(10, "AudioPts %lld\n", call->Pts); + unsigned int HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = HeaderLength; @@ -208,31 +217,38 @@ static int _writeData(void *_call, int type) static int writeDataADTS(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + aac_printf(10, "\n"); + if (call == NULL) { aac_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { aac_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { aac_err("file pointer < 0. ignoring ...\n"); return 0; } + if ((call->private_data && 0 == strncmp("ADTS", call->private_data, call->private_size)) || HasADTSHeader(call->data, call->len)) { return _writeData(_call, 0); } + uint32_t PacketLength = call->len + AAC_HEADER_LENGTH; uint8_t PesHeader[PES_MAX_HEADER_SIZE + AAC_HEADER_LENGTH]; uint32_t headerSize = InsertPesHeader(PesHeader, PacketLength, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); uint8_t *pExtraData = &PesHeader[headerSize]; + aac_printf(10, "AudioPts %lld\n", call->Pts); if (call->private_data == NULL) { @@ -243,6 +259,7 @@ static int writeDataADTS(void *_call) { memcpy(pExtraData, call->private_data, AAC_HEADER_LENGTH); } + pExtraData[3] &= 0xC0; /* frame size over last 2 bits */ pExtraData[3] |= (PacketLength & 0x1800) >> 11; @@ -255,33 +272,41 @@ static int writeDataADTS(void *_call) /* buffer fullness(0x7FF for VBR) continued over 6 first bits + 2 zeros for * number of raw data blocks */ pExtraData[6] = 0xFC; + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = headerSize + AAC_HEADER_LENGTH; iov[1].iov_base = call->data; iov[1].iov_len = call->len; + return writev(call->fd, iov, 2); } static int writeDataLATM(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + aac_printf(10, "\n"); + if (call == NULL) { aac_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { aac_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->private_data && 0 == strncmp("LATM", call->private_data, call->private_size)) { return _writeData(_call, 1); } + aac_printf(10, "AudioPts %lld\n", call->Pts); + if (!pLATMCtx) { pLATMCtx = malloc(sizeof(LATMContext)); @@ -289,11 +314,13 @@ static int writeDataLATM(void *_call) pLATMCtx->mod = 14; pLATMCtx->counter = 0; } + if (!pLATMCtx) { aac_err("parsing NULL pLATMCtx. ignoring...\n"); return 0; } + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; int ret = latmenc_decode_extradata(pLATMCtx, call->private_data, call->private_size); if (ret) @@ -309,14 +336,19 @@ static int writeDataLATM(void *_call) aac_err("latm_write_packet failed. ignoring...\n"); return 0; } + unsigned int HeaderLength = InsertPesHeader(PesHeader, pLATMCtx->len + 3, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); + struct iovec iov[3]; iov[0].iov_base = PesHeader; iov[0].iov_len = HeaderLength; + iov[1].iov_base = pLATMCtx->loas_header; iov[1].iov_len = 3; + iov[2].iov_base = pLATMCtx->buffer; iov[2].iov_len = pLATMCtx->len; + return writev(call->fd, iov, 3); } diff --git a/libeplayer3-arm/output/writer/sh4/ac3.c b/libeplayer3-arm/output/writer/sh4/ac3.c index cf50f6b..3ff3df0 100644 --- a/libeplayer3-arm/output/writer/sh4/ac3.c +++ b/libeplayer3-arm/output/writer/sh4/ac3.c @@ -98,29 +98,38 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + ac3_printf(10, "\n"); + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + if (call == NULL) { ac3_err("call data is NULL...\n"); return 0; } + ac3_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { ac3_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { ac3_err("file pointer < 0. ignoring ...\n"); return 0; } + struct iovec iov[2]; + iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, call->len, PRIVATE_STREAM_1_PES_START_CODE, call->Pts, 0); iov[1].iov_base = call->data; iov[1].iov_len = call->len; + return writev(call->fd, iov, 2); } diff --git a/libeplayer3-arm/output/writer/sh4/divx.c b/libeplayer3-arm/output/writer/sh4/divx.c index 904b7af..e18538d 100644 --- a/libeplayer3-arm/output/writer/sh4/divx.c +++ b/libeplayer3-arm/output/writer/sh4/divx.c @@ -101,6 +101,7 @@ static uint8_t updateCodecData(uint8_t *data, int32_t size) { static uint8_t *oldData = NULL; static int32_t oldSize = 0; + uint8_t update = 0; if (data != NULL && size > 0) { @@ -121,6 +122,7 @@ static uint8_t updateCodecData(uint8_t *data, int32_t size) } } } + if (update) { if (oldData != NULL) @@ -131,43 +133,56 @@ static uint8_t updateCodecData(uint8_t *data, int32_t size) memcpy(oldData, data, size); oldSize = size; } + return update; } static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + divx_printf(10, "\n"); + if (call == NULL) { divx_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { divx_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { divx_err("file pointer < 0. ignoring ...\n"); return 0; } + divx_printf(10, "VideoPts %lld\n", call->Pts); + struct iovec iov[4]; int ic = 0; iov[ic].iov_base = PesHeader; iov[ic++].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0); + if (updateCodecData(call->private_data, call->private_size)) { iov[ic].iov_base = call->private_data; iov[ic++].iov_len = call->private_size; } + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; + int len = writev(call->fd, iov, ic); + divx_printf(10, "xvid_Write < len=%d\n", len); + return len; } diff --git a/libeplayer3-arm/output/writer/sh4/divx2.c b/libeplayer3-arm/output/writer/sh4/divx2.c index a658416..c7b8654 100644 --- a/libeplayer3-arm/output/writer/sh4/divx2.c +++ b/libeplayer3-arm/output/writer/sh4/divx2.c @@ -101,6 +101,7 @@ static uint8_t updateCodecData(uint8_t *data, int32_t size) { static uint8_t *oldData = NULL; static int32_t oldSize = 0; + uint8_t update = 0; if (data != NULL && size > 0) { @@ -121,6 +122,7 @@ static uint8_t updateCodecData(uint8_t *data, int32_t size) } } } + if (update) { if (oldData != NULL) @@ -131,12 +133,14 @@ static uint8_t updateCodecData(uint8_t *data, int32_t size) memcpy(oldData, data, size); oldSize = size; } + return update; } static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; unsigned char FakeHeaders[64]; // 64bytes should be enough to make the fake headers unsigned int FakeHeaderLength; @@ -144,26 +148,34 @@ static int writeData(void *_call) unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE; unsigned int usecPerFrame = 41708; /* Hellmaster1024: default value */ BitPacker_t ld = {FakeHeaders, 0, 32}; + divx_printf(10, "\n"); + if (call == NULL) { divx_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { divx_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { divx_err("file pointer < 0. ignoring ...\n"); return 0; } + divx_printf(10, "AudioPts %lld\n", call->Pts); + usecPerFrame = 1000000000 / call->FrameRate; divx_printf(10, "Microsecends per frame = %d\n", usecPerFrame); + memset(FakeHeaders, 0, sizeof(FakeHeaders)); + /* Create info record for frame parser */ /* divx4 & 5 VOS @@ -177,23 +189,30 @@ static int writeData(void *_call) PutBits(&ld, usecPerFrame, 32); // microseconds per frame FlushBits(&ld); + FakeHeaderLength = (ld.Ptr - (FakeHeaders)); + struct iovec iov[4]; int ic = 0; iov[ic].iov_base = PesHeader; iov[ic++].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, FakeStartCode); iov[ic].iov_base = FakeHeaders; iov[ic++].iov_len = FakeHeaderLength; + if (initialHeader) { iov[ic].iov_base = call->private_data; iov[ic++].iov_len = call->private_size; initialHeader = 0; } + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; + int len = writev(call->fd, iov, ic); + divx_printf(10, "xvid_Write < len=%d\n", len); + return len; } diff --git a/libeplayer3-arm/output/writer/sh4/dts.c b/libeplayer3-arm/output/writer/sh4/dts.c index 25bd117..fb2a21f 100644 --- a/libeplayer3-arm/output/writer/sh4/dts.c +++ b/libeplayer3-arm/output/writer/sh4/dts.c @@ -102,26 +102,34 @@ static int reset() static int32_t writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + uint8_t PesHeader[PES_AUDIO_HEADER_SIZE]; + dts_printf(10, "\n"); + if (call == NULL) { dts_err("call data is NULL...\n"); return 0; } + dts_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { dts_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { dts_err("file pointer < 0. ignoring ...\n"); return 0; } + uint8_t *Data = call->data; int32_t Size = call->len; + #ifdef CHECK_FOR_DTS_HD int32_t pos = 0; while ((pos + 4) <= Size) @@ -135,6 +143,7 @@ static int32_t writeData(void *_call) ++pos; } #endif + // #define DO_BYTESWAP #ifdef DO_BYTESWAP /* 16-bit byte swap all data before injecting it */ @@ -145,11 +154,13 @@ static int32_t writeData(void *_call) Data[i + 1] = Tmp; } #endif + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, Size, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); iov[1].iov_base = Data; iov[1].iov_len = Size; + int32_t len = writev(call->fd, iov, 2); dts_printf(10, "< len %d\n", len); return len; diff --git a/libeplayer3-arm/output/writer/sh4/h263.c b/libeplayer3-arm/output/writer/sh4/h263.c index 86430df..466d720 100644 --- a/libeplayer3-arm/output/writer/sh4/h263.c +++ b/libeplayer3-arm/output/writer/sh4/h263.c @@ -97,39 +97,52 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; int len = 0; + h263_printf(10, "\n"); + if (call == NULL) { h263_err("call data is NULL...\n"); return 0; } + h263_printf(10, "VideoPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { h263_err("NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { h263_err("file pointer < 0. ignoring ...\n"); return 0; } + int HeaderLength = InsertPesHeader(PesHeader, call->len, H263_VIDEO_PES_START_CODE, call->Pts, 0); + int PrivateHeaderLength = InsertVideoPrivateDataHeader(&PesHeader[HeaderLength], call->len); + int PesLength = PesHeader[PES_LENGTH_BYTE_0] + (PesHeader[PES_LENGTH_BYTE_1] << 8) + PrivateHeaderLength; + PesHeader[PES_LENGTH_BYTE_0] = PesLength & 0xff; PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff; PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength; PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT; + HeaderLength += PrivateHeaderLength; + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = HeaderLength; iov[1].iov_base = call->data; iov[1].iov_len = call->len; len = writev(call->fd, iov, 2); + h263_printf(10, "< len %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/sh4/h264.c b/libeplayer3-arm/output/writer/sh4/h264.c index 482b219..39a6afa 100644 --- a/libeplayer3-arm/output/writer/sh4/h264.c +++ b/libeplayer3-arm/output/writer/sh4/h264.c @@ -113,34 +113,45 @@ static int avc3 = 0; static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, uint8_t *pData, uint32_t dataSize) { uint8_t *aExtraData = *ppExtraData; + if (aExtraData[0] != 1 || !pData) { // Not AVCC or nothing to update with. return -1; } + int32_t nalsize = (aExtraData[4] & 3) + 1; + uint8_t sps[256]; uint8_t spsIdx = 0; + uint8_t numSps = 0; + uint8_t pps[256]; uint8_t ppsIdx = 0; + uint8_t numPps = 0; + if (nalsize != 4) { return -1; } + // Find SPS and PPS NALUs in AVCC data uint8_t *d = pData; while (d + 4 < pData + dataSize) { uint32_t nalLen = ReadUint32(d); + uint8_t nalType = d[4] & 0x1f; if (nalType == 7) { /* SPS */ + // 16 bits size sps[spsIdx++] = (uint8_t)(0xFF & (nalLen >> 8)); sps[spsIdx++] = (uint8_t)(0xFF & nalLen); + if (spsIdx + nalLen >= sizeof(sps)) { h264_err("SPS no free space to copy...\n"); @@ -148,15 +159,19 @@ static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, } memcpy(&(sps[spsIdx]), d + 4, nalLen); spsIdx += nalLen; + numSps += 1; + h264_printf(10, "SPS len[%u]...\n", nalLen); } else if (nalType == 8) { /* PPS */ + // 16 bits size pps[ppsIdx++] = (uint8_t)(0xFF & (nalLen >> 8)); pps[ppsIdx++] = (uint8_t)(0xFF & nalLen); + if (ppsIdx + nalLen >= sizeof(sps)) { h264_err("PPS not free space to copy...\n"); @@ -164,7 +179,9 @@ static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, } memcpy(&(pps[ppsIdx]), d + 4, nalLen); ppsIdx += nalLen; + numPps += 1; + h264_printf(10, "PPS len[%u]...\n", nalLen); } d += 4 + nalLen; @@ -177,18 +194,21 @@ static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, aExtraData[idx++] = sps[4]; // profile compat aExtraData[idx++] = sps[5]; // level aExtraData[idx++] = 0xff; // nal size - 1 + aExtraData[idx++] = 0xe0 | numSps; if (numSps) { memcpy(&(aExtraData[idx]), sps, spsIdx); idx += spsIdx; } + aExtraData[idx++] = numPps; if (numPps) { memcpy(&(aExtraData[idx]), pps, ppsIdx); idx += ppsIdx; } + h264_printf(10, "aExtraData len[%u]...\n", idx); *pExtraDataSize = idx; return 0; @@ -204,6 +224,7 @@ static int32_t reset() static int32_t writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + uint8_t PesHeader[PES_MAX_HEADER_SIZE]; uint64_t VideoPts; uint32_t TimeDelta; @@ -212,25 +233,31 @@ static int32_t writeData(void *_call) int32_t ic = 0; struct iovec iov[128]; h264_printf(10, "\n"); + if (call == NULL) { h264_err("call data is NULL...\n"); return 0; } + TimeDelta = call->FrameRate; TimeScale = call->FrameScale; VideoPts = call->Pts; + h264_printf(10, "VideoPts %lld - %d %d\n", call->Pts, TimeDelta, TimeScale); + if ((call->data == NULL) || (call->len <= 0)) { h264_err("NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { h264_err("file pointer < 0. ignoring ...\n"); return 0; } + /* AnnexA */ if (!avc3 && ((1 < call->private_size && 0 == call->private_data[0]) || (call->len > 3) && ((call->data[0] == 0x00 && call->data[1] == 0x00 && call->data[2] == 0x00 && call->data[3] == 0x01) || @@ -238,6 +265,7 @@ static int32_t writeData(void *_call) { uint32_t PacketLength = 0; uint32_t FakeStartCode = /*(call->Version << 8) | */PES_VERSION_FAKE_START_CODE; + iov[ic++].iov_base = PesHeader; initialHeader = 0; if (initialHeader) @@ -247,16 +275,20 @@ static int32_t writeData(void *_call) iov[ic++].iov_len = call->private_size; PacketLength += call->private_size; } + iov[ic].iov_base = ""; iov[ic++].iov_len = 1; + iov[ic].iov_base = call->data; iov[ic++].iov_len = call->len; PacketLength += call->len; + /*Hellmaster1024: some packets will only be accepted by the player if we send one byte more than data is available. The content of this byte does not matter. It will be ignored by the player */ iov[ic].iov_base = "\0"; iov[ic++].iov_len = 1; + iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, FakeStartCode); int ret = writev(call->fd, iov, ic); return ret; @@ -266,6 +298,7 @@ static int32_t writeData(void *_call) h264_err("No valid private data available!\n"); return 0; } + if (initialHeader) { uint8_t *private_data = call->private_data; @@ -276,8 +309,11 @@ static int32_t writeData(void *_call) unsigned int ParamOffset; unsigned int InitialHeaderLength = 0; unsigned int ParametersLength; + ParametersLength = 0; + unsigned char HeaderData[19]; + if (private_size <= sizeof(avcC_t)) { UpdateExtraData(&private_data, &private_size, call->data, call->len); @@ -287,6 +323,7 @@ static int32_t writeData(void *_call) avcCHeader = (avcC_t *)private_data; } } + HeaderData[ParametersLength++] = 0x00; // Start code HeaderData[ParametersLength++] = 0x00; HeaderData[ParametersLength++] = 0x01; @@ -294,14 +331,17 @@ static int32_t writeData(void *_call) // Container message version - changes when/if we vary the format of the message HeaderData[ParametersLength++] = CONTAINER_PARAMETERS_VERSION; HeaderData[ParametersLength++] = 0xff; // Field separator + if (TimeDelta == 0xffffffff) TimeDelta = (TimeScale > 1000) ? 1001 : 1; + HeaderData[ParametersLength++] = (TimeScale >> 24) & 0xff; // Output the timescale HeaderData[ParametersLength++] = (TimeScale >> 16) & 0xff; HeaderData[ParametersLength++] = 0xff; HeaderData[ParametersLength++] = (TimeScale >> 8) & 0xff; HeaderData[ParametersLength++] = TimeScale & 0xff; HeaderData[ParametersLength++] = 0xff; + HeaderData[ParametersLength++] = (TimeDelta >> 24) & 0xff; // Output frame period HeaderData[ParametersLength++] = (TimeDelta >> 16) & 0xff; HeaderData[ParametersLength++] = 0xff; @@ -309,7 +349,9 @@ static int32_t writeData(void *_call) HeaderData[ParametersLength++] = TimeDelta & 0xff; HeaderData[ParametersLength++] = 0xff; HeaderData[ParametersLength++] = 0x80; // Rsbp trailing bits + assert(ParametersLength <= sizeof(HeaderData)); + ic = 0; iov[ic].iov_base = PesHeader; iov[ic++].iov_len = InsertPesHeader(PesHeader, ParametersLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0); @@ -320,8 +362,10 @@ static int32_t writeData(void *_call) { return len; } + NalLengthBytes = (avcCHeader->NalLengthMinusOne & 0x03) + 1; ParamSets = avcCHeader->NumParamSets & 0x1f; + h264_printf(20, "avcC contents:\n"); h264_printf(20, " version: %d\n", avcCHeader->Version); h264_printf(20, " profile: %d\n", avcCHeader->Profile); @@ -329,13 +373,16 @@ static int32_t writeData(void *_call) h264_printf(20, " level: %d\n", avcCHeader->Level); h264_printf(20, " nal length bytes: %d\n", NalLengthBytes); h264_printf(20, " number of sequence param sets: %d\n", ParamSets); + ParamOffset = 0; ic = 0; iov[ic++].iov_base = PesHeader; for (i = 0; i < ParamSets; i++) { unsigned int PsLength = (avcCHeader->Params[ParamOffset] << 8) + avcCHeader->Params[ParamOffset + 1]; + h264_printf(20, " sps %d has length %d\n", i, PsLength); + iov[ic].iov_base = (char *)Head; iov[ic++].iov_len = sizeof(Head); InitialHeaderLength += sizeof(Head); @@ -344,13 +391,18 @@ static int32_t writeData(void *_call) InitialHeaderLength += PsLength; ParamOffset += PsLength + 2; } + ParamSets = avcCHeader->Params[ParamOffset]; + h264_printf(20, " number of picture param sets: %d\n", ParamSets); + ParamOffset++; for (i = 0; i < ParamSets; i++) { unsigned int PsLength = (avcCHeader->Params[ParamOffset] << 8) + avcCHeader->Params[ParamOffset + 1]; + h264_printf(20, " pps %d has length %d\n", i, PsLength); + iov[ic].iov_base = (char *) Head; iov[ic++].iov_len = sizeof(Head); InitialHeaderLength += sizeof(Head); @@ -359,27 +411,34 @@ static int32_t writeData(void *_call) InitialHeaderLength += PsLength; ParamOffset += PsLength + 2; } + iov[0].iov_len = InsertPesHeader(PesHeader, InitialHeaderLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0); ssize_t l = writev(call->fd, iov, ic); + if (private_data != call->private_data) { free(private_data); } + if (l < 0) { return l; } + len += l; initialHeader = 0; } + unsigned int SampleSize = call->len; unsigned int NalStart = 0; unsigned int VideoPosition = 0; + do { unsigned int NalLength; unsigned char NalData[4]; int NalPresent = 1; + memcpy(NalData, call->data + VideoPosition, NalLengthBytes); VideoPosition += NalLengthBytes; NalStart += NalLengthBytes; @@ -398,11 +457,14 @@ static int32_t writeData(void *_call) NalLength = (NalData[0] << 24) | (NalData[1] << 16) | (NalData[2] << 8) | (NalData[3]); break; } + h264_printf(20, "NalStart = %u + NalLength = %u > SampleSize = %u\n", NalStart, NalLength, SampleSize); + if (NalStart + NalLength > SampleSize) { h264_printf(20, "nal length past end of buffer - size %u frame offset %u left %u\n", NalLength, NalStart, SampleSize - NalStart); + NalStart = SampleSize; } else @@ -410,30 +472,37 @@ static int32_t writeData(void *_call) NalStart += NalLength; ic = 0; iov[ic++].iov_base = PesHeader; + if (NalPresent) { NalPresent = 0; iov[ic].iov_base = (char *)Head; iov[ic++].iov_len = sizeof(Head); } + iov[ic].iov_base = call->data + VideoPosition; iov[ic++].iov_len = NalLength; VideoPosition += NalLength; + h264_printf(20, " pts=%llu\n", VideoPts); + iov[0].iov_len = InsertPesHeader(PesHeader, NalLength, MPEG_VIDEO_PES_START_CODE, VideoPts, 0); ssize_t l = writev(call->fd, iov, ic); if (l < 0) return l; len += l; + VideoPts = INVALID_PTS_VALUE; } } while (NalStart < SampleSize); + if (len < 0) { h264_err("error writing data errno = %d\n", errno); h264_err("%s\n", strerror(errno)); } + h264_printf(10, "< len %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/sh4/mp3.c b/libeplayer3-arm/output/writer/sh4/mp3.c index f66bb41..7ed7d02 100644 --- a/libeplayer3-arm/output/writer/sh4/mp3.c +++ b/libeplayer3-arm/output/writer/sh4/mp3.c @@ -97,30 +97,39 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + mp3_printf(10, "\n"); + if (call == NULL) { mp3_err("call data is NULL...\n"); return 0; } + mp3_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { mp3_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { mp3_err("file pointer < 0. ignoring ...\n"); return 0; } + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); iov[1].iov_base = call->data; iov[1].iov_len = call->len; + int len = writev(call->fd, iov, 2); + mp3_printf(10, "mp3_Write-< len=%d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/sh4/mpeg2.c b/libeplayer3-arm/output/writer/sh4/mpeg2.c index 2fd8ad6..cb1f928 100644 --- a/libeplayer3-arm/output/writer/sh4/mpeg2.c +++ b/libeplayer3-arm/output/writer/sh4/mpeg2.c @@ -97,37 +97,49 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + int len = 0; unsigned int Position = 0; + mpeg2_printf(10, "\n"); + if (call == NULL) { mpeg2_err("call data is NULL...\n"); return 0; } + mpeg2_printf(10, "VideoPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { mpeg2_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { mpeg2_err("file pointer < 0. ignoring ...\n"); return 0; } + while (Position < call->len) { int32_t PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ? (call->len - Position) : MAX_PES_PACKET_SIZE; + int32_t Remaining = call->len - Position - PacketLength; + mpeg2_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position); + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, 0xe0, call->Pts, 0); iov[1].iov_base = call->data + Position; iov[1].iov_len = PacketLength; + ssize_t l = writev(call->fd, iov, 2); if (l < 0) { @@ -135,9 +147,11 @@ static int writeData(void *_call) break; } len += l; + Position += PacketLength; call->Pts = INVALID_PTS_VALUE; } + mpeg2_printf(10, "< len %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/sh4/pcm.c b/libeplayer3-arm/output/writer/sh4/pcm.c index 5b752dd..4a7103f 100644 --- a/libeplayer3-arm/output/writer/sh4/pcm.c +++ b/libeplayer3-arm/output/writer/sh4/pcm.c @@ -124,10 +124,13 @@ static int32_t prepareClipPlay(int32_t uNoOfChannels, int32_t uSampleRate, int32 uBitsPerSample/*Format->wBitsPerSample*/, (uBitsPerSample/*Format->wBitsPerSample*/ / 8) ); + SubFrameLen = 0; SubFramesPerPES = 0; breakBufferFillSize = 0; + memcpy(lpcm_prv, clpcm_prv, sizeof(lpcm_prv)); + //figure out size of subframe //and set up sample rate switch (uSampleRate) @@ -158,14 +161,18 @@ static int32_t prepareClipPlay(int32_t uNoOfChannels, int32_t uSampleRate, int32 default: break; } + SubFrameLen *= uNoOfChannels; SubFrameLen *= (uBitsPerSample / 8); + //rewrite PES size to have as many complete subframes per PES as we can // FIXME: PES header size was hardcoded to 18 in previous code. Actual size returned by InsertPesHeader is 14. SubFramesPerPES = ((2048 - 18) - sizeof(lpcm_prv)) / SubFrameLen; SubFrameLen *= SubFramesPerPES; + //set number of channels lpcm_prv[10] = uNoOfChannels - 1; + switch (uBitsPerSample) { case 24: @@ -176,6 +183,7 @@ static int32_t prepareClipPlay(int32_t uNoOfChannels, int32_t uSampleRate, int32 printf("inappropriate bits per sample (%d) - must be 16 or 24\n", uBitsPerSample); return 1; } + return 0; } @@ -188,25 +196,33 @@ static int32_t reset() static int32_t writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + pcm_printf(10, "\n"); + if (!call) { pcm_err("call data is NULL...\n"); return 0; } + pcm_printf(10, "AudioPts %lld\n", call->Pts); + if (!call->data || (call->len <= 0)) { pcm_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { pcm_err("file pointer < 0. ignoring ...\n"); return 0; } + pcmPrivateData_t *pcmPrivateData = (pcmPrivateData_t *)call->private_data; + if (initialHeader) { uint32_t codecID = (uint32_t)pcmPrivateData->ffmpeg_codec_id; @@ -240,11 +256,14 @@ static int32_t writeData(void *_call) initialHeader = 0; prepareClipPlay(pcmPrivateData->channels, pcmPrivateData->sample_rate, pcmPrivateData->bits_per_coded_sample, LE); } + uint8_t *buffer = call->data; uint32_t size = call->len; + uint32_t n; uint8_t *injectBuffer = malloc(SubFrameLen); uint32_t pos; + for (pos = 0; pos < size;) { //printf("PCM %s - Position=%d\n", __FUNCTION__, pos); @@ -255,6 +274,7 @@ static int32_t writeData(void *_call) //printf("PCM %s - Unplayed=%d\n", __FUNCTION__, breakBufferFillSize); break; } + //get first PES's worth if (breakBufferFillSize > 0) { @@ -268,12 +288,15 @@ static int32_t writeData(void *_call) memcpy(injectBuffer, &buffer[pos], sizeof(uint8_t)*SubFrameLen); pos += SubFrameLen; } + struct iovec iov[3]; iov[0].iov_base = PesHeader; iov[1].iov_base = lpcm_prv; iov[1].iov_len = sizeof(lpcm_prv); + iov[2].iov_base = injectBuffer; iov[2].iov_len = SubFrameLen; + //write the PCM data if (16 == pcmPrivateData->bits_per_coded_sample) { @@ -305,8 +328,10 @@ static int32_t writeData(void *_call) p[ 8] = t; } } + //increment err... subframe count? lpcm_prv[1] = ((lpcm_prv[1] + SubFramesPerPES) & 0x1F); + iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len + iov[2].iov_len, PCM_PES_START_CODE, call->Pts, 0); int32_t len = writev(call->fd, iov, 3); if (len < 0) @@ -315,6 +340,7 @@ static int32_t writeData(void *_call) } } free(injectBuffer); + return size; } diff --git a/libeplayer3-arm/output/writer/sh4/pes.c b/libeplayer3-arm/output/writer/sh4/pes.c index 8df20a8..12a7bd6 100644 --- a/libeplayer3-arm/output/writer/sh4/pes.c +++ b/libeplayer3-arm/output/writer/sh4/pes.c @@ -70,23 +70,30 @@ int InsertVideoPrivateDataHeader(unsigned char *data, int payload_size) { BitPacker_t ld2 = {data, 0, 32}; int i; + PutBits(&ld2, PES_PRIVATE_DATA_FLAG, 8); PutBits(&ld2, payload_size & 0xff, 8); PutBits(&ld2, (payload_size >> 8) & 0xff, 8); PutBits(&ld2, (payload_size >> 16) & 0xff, 8); + for (i = 4; i < (PES_PRIVATE_DATA_LENGTH + 1); i++) PutBits(&ld2, 0, 8); + FlushBits(&ld2); + return PES_PRIVATE_DATA_LENGTH + 1; + } int InsertPesHeader(unsigned char *data, int size, unsigned char stream_id, unsigned long long int pts, int pic_start_code) { BitPacker_t ld2 = {data, 0, 32}; + if (size > (MAX_PES_PACKET_SIZE - 13)) { size = -1; // unbounded } + PutBits(&ld2, 0x0, 8); PutBits(&ld2, 0x0, 8); PutBits(&ld2, 0x1, 8); // Start Code @@ -108,6 +115,7 @@ int InsertPesHeader(unsigned char *data, int size, unsigned char stream_id, unsi PutBits(&ld2, 0x0, 1); // Copyright PutBits(&ld2, 0x0, 1); // Original or Copy //7 = 6+1 + if (pts != INVALID_PTS_VALUE) { PutBits(&ld2, 0x2, 2); @@ -116,6 +124,7 @@ int InsertPesHeader(unsigned char *data, int size, unsigned char stream_id, unsi { PutBits(&ld2, 0x0, 2); // PTS_DTS flag } + PutBits(&ld2, 0x0, 1); // ESCR_flag PutBits(&ld2, 0x0, 1); // ES_rate_flag PutBits(&ld2, 0x0, 1); // DSM_trick_mode_flag @@ -123,11 +132,13 @@ int InsertPesHeader(unsigned char *data, int size, unsigned char stream_id, unsi PutBits(&ld2, 0x0, 1); // PES_CRC_flag PutBits(&ld2, 0x0, 1); // PES_extension_flag //8 = 7+1 + if (pts != INVALID_PTS_VALUE) PutBits(&ld2, 0x5, 8); else PutBits(&ld2, 0x0, 8); // PES_header_data_length //9 = 8+1 + if (pts != INVALID_PTS_VALUE) { PutBits(&ld2, 0x2, 4); @@ -139,6 +150,7 @@ int InsertPesHeader(unsigned char *data, int size, unsigned char stream_id, unsi PutBits(&ld2, 0x1, 1); } //14 = 9+5 + if (pic_start_code) { PutBits(&ld2, 0x0, 8); @@ -148,6 +160,8 @@ int InsertPesHeader(unsigned char *data, int size, unsigned char stream_id, unsi PutBits(&ld2, (pic_start_code >> 8) & 0xff, 8); // For any extra information (like in mpeg4p2, the pic_start_code) //14 + 4 = 18 } + FlushBits(&ld2); + return (ld2.Ptr - data); } diff --git a/libeplayer3-arm/output/writer/sh4/vc1.c b/libeplayer3-arm/output/writer/sh4/vc1.c index baa8129..4865e9f 100644 --- a/libeplayer3-arm/output/writer/sh4/vc1.c +++ b/libeplayer3-arm/output/writer/sh4/vc1.c @@ -127,25 +127,31 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + int len = 0; vc1_printf(10, "\n"); + if (call == NULL) { vc1_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { vc1_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { vc1_err("file pointer < 0. ignoring ...\n"); return 0; } + vc1_printf(10, "VideoPts %lld\n", call->Pts); vc1_printf(10, "Got Private Size %d\n", call->private_size); + if (initialHeader) { unsigned char PesHeader[PES_MAX_HEADER_SIZE]; @@ -153,18 +159,25 @@ static int writeData(void *_call) unsigned char *PesPtr; unsigned int crazyFramerate = 0; struct iovec iov[2]; + vc1_printf(10, "Framerate: %u\n", call->FrameRate); vc1_printf(10, "biWidth: %d\n", call->Width); vc1_printf(10, "biHeight: %d\n", call->Height); + crazyFramerate = ((10000000.0 / call->FrameRate) * 1000.0); vc1_printf(10, "crazyFramerate: %u\n", crazyFramerate); + memset(PesPayload, 0, sizeof(PesPayload)); + PesPtr = PesPayload; + memcpy(PesPtr, SequenceLayerStartCode, sizeof(SequenceLayerStartCode)); PesPtr += sizeof(SequenceLayerStartCode); + memcpy(PesPtr, Metadata, sizeof(Metadata)); PesPtr += METADATA_STRUCT_C_START; PesPtr += WMV3_PRIVATE_DATA_LENGTH; + /* Metadata Header Struct A */ *PesPtr++ = (call->Height >> 0) & 0xff; *PesPtr++ = (call->Height >> 8) & 0xff; @@ -174,43 +187,56 @@ static int writeData(void *_call) *PesPtr++ = (call->Width >> 8) & 0xff; *PesPtr++ = (call->Width >> 16) & 0xff; *PesPtr++ = call->Width >> 24; + PesPtr += 12; /* Skip flag word and Struct B first 8 bytes */ + *PesPtr++ = (crazyFramerate >> 0) & 0xff; *PesPtr++ = (crazyFramerate >> 8) & 0xff; *PesPtr++ = (crazyFramerate >> 16) & 0xff; *PesPtr++ = crazyFramerate >> 24; + iov[0].iov_base = PesHeader; iov[1].iov_base = PesPayload; iov[1].iov_len = PesPtr - PesPayload; iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0); len = writev(call->fd, iov, 2); + /* For VC1 the codec private data is a standard vc1 sequence header so we just copy it to the output */ iov[0].iov_base = PesHeader; iov[1].iov_base = call->private_data; iov[1].iov_len = call->private_size; iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0); len = writev(call->fd, iov, 2); + initialHeader = 0; } + if (call->len > 0 && call->data) { uint32_t Position = 0; uint8_t insertSampleHeader = 1; + while (Position < call->len) { int32_t PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ? (call->len - Position) : MAX_PES_PACKET_SIZE; + int32_t Remaining = call->len - Position - PacketLength; + vc1_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position); + uint8_t PesHeader[PES_MAX_HEADER_SIZE]; int32_t HeaderLength = InsertPesHeader(PesHeader, PacketLength, VC1_VIDEO_PES_START_CODE, call->Pts, 0); + if (insertSampleHeader) { const uint8_t Vc1FrameStartCode[] = {0, 0, 1, VC1_FRAME_START_CODE}; + if (!FrameHeaderSeen && (call->len > 3) && (memcmp(call->data, Vc1FrameStartCode, 4) == 0)) { FrameHeaderSeen = 1; } + if (!FrameHeaderSeen) { memcpy(&PesHeader[HeaderLength], Vc1FrameStartCode, sizeof(Vc1FrameStartCode)); @@ -218,11 +244,13 @@ static int writeData(void *_call) } insertSampleHeader = 0; } + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = HeaderLength; iov[1].iov_base = call->data + Position; iov[1].iov_len = PacketLength; + ssize_t l = writev(call->fd, iov, 2); if (l < 0) { @@ -230,10 +258,12 @@ static int writeData(void *_call) break; } len += l; + Position += PacketLength; call->Pts = INVALID_PTS_VALUE; } } + vc1_printf(10, "< %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/sh4/vorbis.c b/libeplayer3-arm/output/writer/sh4/vorbis.c index 0b09940..3ed1cb2 100644 --- a/libeplayer3-arm/output/writer/sh4/vorbis.c +++ b/libeplayer3-arm/output/writer/sh4/vorbis.c @@ -50,8 +50,6 @@ /* Makros/Constants */ /* ***************************** */ -//#define SAM_WITH_DEBUG - #ifdef SAM_WITH_DEBUG #define VORBIS_DEBUG #else @@ -98,30 +96,42 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + vorbis_printf(10, "\n"); + if (call == NULL) { vorbis_err("call data is NULL...\n"); return 0; } + vorbis_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { vorbis_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { vorbis_err("file pointer < 0. ignoring ...\n"); return 0; } + int HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); + unsigned char *PacketStart = malloc(call->len + HeaderLength); + memcpy(PacketStart, PesHeader, HeaderLength); memcpy(PacketStart + HeaderLength, call->data, call->len); + int len = write(call->fd, PacketStart, call->len + HeaderLength); + free(PacketStart); + vorbis_printf(10, "vorbis_Write-< len=%d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/sh4/wma.c b/libeplayer3-arm/output/writer/sh4/wma.c index 39a42a9..4b92ac5 100644 --- a/libeplayer3-arm/output/writer/sh4/wma.c +++ b/libeplayer3-arm/output/writer/sh4/wma.c @@ -51,8 +51,6 @@ /* Makros/Constants */ /* ***************************** */ -//#define SAM_WITH_DEBUG - #ifdef SAM_WITH_DEBUG #define WMA_DEBUG #else @@ -102,32 +100,41 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + int len = 0; + wma_printf(10, "\n"); + if (call == NULL) { wma_err("call data is NULL...\n"); return 0; } + wma_printf(10, "AudioPts %lld\n", call->Pts); + if ((call->data == NULL) || (call->len <= 0)) { wma_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { wma_err("file pointer < 0. ignoring ...\n"); return 0; } + if (initialHeader) { unsigned char PesHeader[PES_MAX_HEADER_SIZE]; + if ((call->private_size <= 0) || (call->private_data == NULL)) { wma_err("private NULL.\n"); return -1; } + struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader(PesHeader, call->private_size, MPEG_AUDIO_PES_START_CODE, 0, 0); @@ -136,6 +143,7 @@ static int writeData(void *_call) len = writev(call->fd, iov, 2); initialHeader = 0; } + if (len > -1 && call->len > 0 && call->data) { unsigned char PesHeader[PES_MAX_HEADER_SIZE]; @@ -144,10 +152,13 @@ static int writeData(void *_call) iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); iov[1].iov_base = call->data; iov[1].iov_len = call->len; + ssize_t l = writev(call->fd, iov, 2); len = (l > -1) ? len + l : l; } + wma_printf(10, "wma < %d\n", len); + return len; } diff --git a/libeplayer3-arm/output/writer/sh4/wmv.c b/libeplayer3-arm/output/writer/sh4/wmv.c index cc61134..9a644d9 100644 --- a/libeplayer3-arm/output/writer/sh4/wmv.c +++ b/libeplayer3-arm/output/writer/sh4/wmv.c @@ -128,31 +128,40 @@ static int reset() static int writeData(void *_call) { WriterAVCallData_t *call = (WriterAVCallData_t *) _call; + awmv_t private_data; int len = 0; + wmv_printf(10, "\n"); + if (call == NULL) { wmv_err("call data is NULL...\n"); return 0; } + if ((call->data == NULL) || (call->len <= 0)) { wmv_err("parsing NULL Data. ignoring...\n"); return 0; } + if (call->fd < 0) { wmv_err("file pointer < 0. ignoring ...\n"); return 0; } + wmv_printf(10, "VideoPts %lld\n", call->Pts); wmv_printf(10, "Got Private Size %d\n", call->private_size); + memcpy(private_data.privateData, call->private_data, call->private_size > WMV3_PRIVATE_DATA_LENGTH ? WMV3_PRIVATE_DATA_LENGTH : call->private_size); + private_data.width = call->Width; private_data.height = call->Height; private_data.framerate = call->FrameRate; + #define PES_MIN_HEADER_SIZE 9 if (initialHeader) { @@ -160,16 +169,22 @@ static int writeData(void *_call) unsigned char *PesPtr; unsigned int MetadataLength; unsigned int crazyFramerate = 0; + wmv_printf(10, "Framerate: %u\n", private_data.framerate); wmv_printf(10, "biWidth: %d\n", private_data.width); wmv_printf(10, "biHeight: %d\n", private_data.height); + crazyFramerate = ((10000000.0 / private_data.framerate) * 1000.0); wmv_printf(10, "crazyFramerate: %u\n", crazyFramerate); + PesPtr = &PesPacket[PES_MIN_HEADER_SIZE]; + memcpy(PesPtr, Metadata, sizeof(Metadata)); PesPtr += METADATA_STRUCT_C_START; + memcpy(PesPtr, private_data.privateData, WMV3_PRIVATE_DATA_LENGTH); PesPtr += WMV3_PRIVATE_DATA_LENGTH; + /* Metadata Header Struct A */ *PesPtr++ = (private_data.height >> 0) & 0xff; *PesPtr++ = (private_data.height >> 8) & 0xff; @@ -179,16 +194,23 @@ static int writeData(void *_call) *PesPtr++ = (private_data.width >> 8) & 0xff; *PesPtr++ = (private_data.width >> 16) & 0xff; *PesPtr++ = private_data.width >> 24; + PesPtr += 12; /* Skip flag word and Struct B first 8 bytes */ + *PesPtr++ = (crazyFramerate >> 0) & 0xff; *PesPtr++ = (crazyFramerate >> 8) & 0xff; *PesPtr++ = (crazyFramerate >> 16) & 0xff; *PesPtr++ = crazyFramerate >> 24; + MetadataLength = PesPtr - &PesPacket[PES_MIN_HEADER_SIZE]; + int HeaderLength = InsertPesHeader(PesPacket, MetadataLength, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0); + len = write(call->fd, PesPacket, HeaderLength + MetadataLength); + initialHeader = 0; } + if (call->len > 0 && call->data) { unsigned int Position = 0; @@ -197,12 +219,16 @@ static int writeData(void *_call) { int PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ? (call->len - Position) : MAX_PES_PACKET_SIZE; + int Remaining = call->len - Position - PacketLength; + wmv_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position); + unsigned char PesHeader[PES_MAX_HEADER_SIZE]; memset(PesHeader, '0', PES_MAX_HEADER_SIZE); int HeaderLength = InsertPesHeader(PesHeader, PacketLength, VC1_VIDEO_PES_START_CODE, call->Pts, 0); unsigned char *PacketStart; + if (insertSampleHeader) { unsigned int PesLength; @@ -215,18 +241,23 @@ static int writeData(void *_call) PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff; PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength; PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT; + HeaderLength += PrivateHeaderLength; insertSampleHeader = 0; } + PacketStart = malloc(call->len + HeaderLength); memcpy(PacketStart, PesHeader, HeaderLength); memcpy(PacketStart + HeaderLength, call->data + Position, PacketLength); + len = write(call->fd, PacketStart, PacketLength + HeaderLength); free(PacketStart); + Position += PacketLength; call->Pts = INVALID_PTS_VALUE; } } + wmv_printf(10, "< %d\n", len); return len; } diff --git a/libeplayer3-arm/output/writer/sh4/writer.c b/libeplayer3-arm/output/writer/sh4/writer.c index a9d8548..1ac9cf2 100644 --- a/libeplayer3-arm/output/writer/sh4/writer.c +++ b/libeplayer3-arm/output/writer/sh4/writer.c @@ -100,6 +100,7 @@ static Writer_t *AvailableWriter[] = Writer_t *getWriter(char *encoding) { int i; + for (i = 0; AvailableWriter[i] != NULL; i++) { if (strcmp(AvailableWriter[i]->caps->textEncoding, encoding) == 0) @@ -108,13 +109,16 @@ Writer_t *getWriter(char *encoding) return AvailableWriter[i]; } } + writer_printf(1, "%s: no writer found for \"%s\"\n", __func__, encoding); + return NULL; } Writer_t *getDefaultVideoWriter() { int i; + for (i = 0; AvailableWriter[i] != NULL; i++) { if (strcmp(AvailableWriter[i]->caps->textEncoding, "V_MPEG2") == 0) @@ -123,13 +127,16 @@ Writer_t *getDefaultVideoWriter() return AvailableWriter[i]; } } + writer_printf(1, "%s: no writer found\n", __func__); + return NULL; } Writer_t *getDefaultAudioWriter() { int i; + for (i = 0; AvailableWriter[i] != NULL; i++) { if (strcmp(AvailableWriter[i]->caps->textEncoding, "A_MP3") == 0) @@ -138,6 +145,8 @@ Writer_t *getDefaultAudioWriter() return AvailableWriter[i]; } } + writer_printf(1, "%s: no writer found\n", __func__); + return NULL; } diff --git a/libeplayer3-arm/playback/playback.c b/libeplayer3-arm/playback/playback.c index bac6adb..6ed983e 100644 --- a/libeplayer3-arm/playback/playback.c +++ b/libeplayer3-arm/playback/playback.c @@ -114,7 +114,7 @@ bool PlaybackDieNowRegisterCallback(PlaybackDieNowCallback callback) ret = true; break; } - + if (playbackDieNowCallbacks[i] == NULL) { playbackDieNowCallbacks[i] = callback; @@ -135,6 +135,7 @@ static void SupervisorThread(Context_t *context) { hasThreadStarted = 1; playback_printf(10, ">\n"); + while (context && context->playback && context->playback->isPlaying && !context->playback->abortRequested) { usleep(100000); @@ -158,19 +159,26 @@ static int PlaybackOpen(Context_t *context, PlayFiles_t *pFiles) { PlaybackStop(context); } + char *uri = pFiles->szFirstFile; + playback_printf(10, "URI=%s\n", uri); + if (context->playback->isPlaying) { // shouldn't happen playback_err("playback already running\n"); return cERR_PLAYBACK_ERROR; } + char *extension = NULL; + context->playback->uri = strdup(uri); + context->playback->isFile = 0; context->playback->isHttp = 0; context->playback->noprobe = 0; + if (!strncmp("file://", uri, 7) || !strncmp("myts://", uri, 7)) { context->playback->isFile = 1; @@ -183,6 +191,7 @@ static int PlaybackOpen(Context_t *context, PlayFiles_t *pFiles) { context->playback->noprobe = 0; } + extension = getExtension(context->playback->uri + 7); if (!extension) { @@ -207,6 +216,7 @@ static int PlaybackOpen(Context_t *context, PlayFiles_t *pFiles) free(context->playback->uri); context->playback->uri = tUri; } + if (strstr(uri, ":10000") || strstr(uri, ":31339/id=")) { context->playback->noprobe = 1; @@ -217,6 +227,7 @@ static int PlaybackOpen(Context_t *context, PlayFiles_t *pFiles) playback_err("Unknown stream (%s)\n", uri); return cERR_PLAYBACK_ERROR; } + pFiles->szFirstFile = context->playback->uri; if ((context->container->Command(context, CONTAINER_ADD, extension) < 0) || (!context->container->selectedContainer) || @@ -225,20 +236,26 @@ static int PlaybackOpen(Context_t *context, PlayFiles_t *pFiles) playback_err("CONTAINER_ADD failed\n"); return cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value 0\n"); + return cERR_PLAYBACK_NO_ERROR; } static int PlaybackClose(Context_t *context) { int ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "\n"); + if (context->container->Command(context, CONTAINER_DEL, NULL) < 0) { playback_err("container delete failed\n"); } + context->manager->audio->Command(context, MANAGER_DEL, NULL); context->manager->video->Command(context, MANAGER_DEL, NULL); + context->playback->isPaused = 0; context->playback->isPlaying = 0; context->playback->isForwarding = 0; @@ -250,8 +267,10 @@ static int PlaybackClose(Context_t *context) free(context->playback->uri); context->playback->uri = NULL; } + PlaybackDieNow(2); playback_printf(10, "exiting with value %d\n", ret); + return ret; } @@ -259,13 +278,17 @@ static int PlaybackPlay(Context_t *context) { pthread_attr_t attr; int ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "\n"); + if (!context->playback->isPlaying) { context->playback->AVSync = 1; context->output->Command(context, OUTPUT_AVSYNC, NULL); + context->playback->isCreationPhase = 1; // allows the created thread to go into wait mode ret = context->output->Command(context, OUTPUT_PLAY, NULL); + if (ret != 0) { playback_err("OUTPUT_PLAY failed!\n"); @@ -287,6 +310,7 @@ static int PlaybackPlay(Context_t *context) context->playback->BackWard = 0; context->playback->SlowMotion = 0; context->playback->Speed = 1; + if (hasThreadStarted == 0) { int error; @@ -302,13 +326,17 @@ static int PlaybackPlay(Context_t *context) playback_printf(10, "Created thread\n"); } } + playback_printf(10, "clearing isCreationPhase!\n"); + context->playback->isCreationPhase = 0; // allow thread to go into next state + ret = context->container->selectedContainer->Command(context, CONTAINER_PLAY, NULL); if (ret != 0) { playback_err("CONTAINER_PLAY failed!\n"); } + } } else @@ -316,19 +344,25 @@ static int PlaybackPlay(Context_t *context) playback_err("playback already running\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); + return ret; } static int PlaybackPause(Context_t *context) { int ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "\n"); + if (context->playback->isPlaying && !context->playback->isPaused) { if (context->playback->SlowMotion) context->output->Command(context, OUTPUT_CLEAR, NULL); + context->output->Command(context, OUTPUT_PAUSE, NULL); + context->playback->isPaused = 1; //context->playback->isPlaying = 1; context->playback->isForwarding = 0; @@ -341,6 +375,7 @@ static int PlaybackPause(Context_t *context) playback_err("playback not playing or already in pause mode\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); return ret; } @@ -348,15 +383,19 @@ static int PlaybackPause(Context_t *context) static int32_t PlaybackContinue(Context_t *context) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "\n"); + if (context->playback->isPlaying && (context->playback->isPaused || context->playback->isForwarding || context->playback->BackWard || context->playback->SlowMotion)) { if (context->playback->SlowMotion || context->playback->isForwarding || context->playback->BackWard) context->output->Command(context, OUTPUT_CLEAR, NULL); + if (context->playback->BackWard) context->output->Command(context, OUTPUT_AUDIOMUTE, "0"); + context->playback->isPaused = 0; //context->playback->isPlaying = 1; context->playback->isForwarding = 0; @@ -370,6 +409,7 @@ static int32_t PlaybackContinue(Context_t *context) playback_err("continue not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); return ret; } @@ -378,34 +418,43 @@ static int32_t PlaybackStop(Context_t *context) { int32_t ret = cERR_PLAYBACK_NO_ERROR; int wait_time = 20; + playback_printf(10, "\n"); + PlaybackDieNow(1); + if (context && context->playback && context->playback->isPlaying) { + context->playback->isPaused = 0; context->playback->isPlaying = 0; context->playback->isForwarding = 0; context->playback->BackWard = 0; context->playback->SlowMotion = 0; context->playback->Speed = 0; + context->output->Command(context, OUTPUT_STOP, NULL); context->container->selectedContainer->Command(context, CONTAINER_STOP, NULL); + } else { playback_err("stop not possible\n"); ret = cERR_PLAYBACK_ERROR; } + while ((hasThreadStarted == 1) && (--wait_time) > 0) { playback_printf(10, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time); usleep(100000); } + if (wait_time == 0) { playback_err("Timeout waiting for thread!\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); return ret; } @@ -413,16 +462,22 @@ static int32_t PlaybackStop(Context_t *context) static int32_t PlaybackTerminate(Context_t *context) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + int wait_time = 20; + playback_printf(20, "\n"); + PlaybackDieNow(1); + if (context && context->playback && context->playback->isPlaying) { //First Flush and than delete container, else e2 cant read length of file anymore + if (context->output->Command(context, OUTPUT_FLUSH, NULL) < 0) { playback_err("failed to flush output.\n"); } + context->playback->isPaused = 0; context->playback->isPlaying = 0; context->playback->isForwarding = 0; @@ -435,21 +490,25 @@ static int32_t PlaybackTerminate(Context_t *context) else { playback_err("%p %p %d\n", context, context->playback, context->playback->isPlaying); + /* fixme: konfetti: we should return an error here but this seems to be a condition which * can happen and is not a real error, which leads to a dead neutrino. should investigate * here later. */ } + while ((hasThreadStarted == 1) && (--wait_time) > 0) { playback_printf(10, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time); usleep(100000); } + if (wait_time == 0) { playback_err("Timeout waiting for thread!\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(20, "exiting with value %d\n", ret); return ret; } @@ -457,7 +516,9 @@ static int32_t PlaybackTerminate(Context_t *context) static int PlaybackFastForward(Context_t *context, int *speed) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "speed %d\n", *speed); + /* Audio only forwarding not supported */ if (context->playback->isVideo && !context->playback->isHttp && !context->playback->BackWard && (!context->playback->isPaused || context->playback->isPlaying)) { @@ -477,14 +538,18 @@ static int PlaybackFastForward(Context_t *context, int *speed) playback_err("fast forward not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); + return ret; } static int PlaybackFastBackward(Context_t *context, int *speed) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "speed = %d\n", *speed); + /* Audio only reverse play not supported */ if (context->playback->isVideo && !context->playback->isForwarding && (!context->playback->isPaused || context->playback->isPlaying)) @@ -508,6 +573,7 @@ static int PlaybackFastBackward(Context_t *context, int *speed) context->output->Command(context, OUTPUT_AUDIOMUTE, "1"); playback_printf(1, "S %d B %d\n", context->playback->Speed, context->playback->BackWard); } + context->output->Command(context, OUTPUT_CLEAR, NULL); } else @@ -515,15 +581,19 @@ static int PlaybackFastBackward(Context_t *context, int *speed) playback_err("fast backward not possible\n"); ret = cERR_PLAYBACK_ERROR; } + context->playback->isSeeking = 0; playback_printf(10, "exiting with value %d\n", ret); + return ret; } static int32_t PlaybackSlowMotion(Context_t *context, int *speed) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "\n"); + //Audio only forwarding not supported if (context->playback->isVideo && !context->playback->isHttp && context->playback->isPlaying) { @@ -549,14 +619,18 @@ static int32_t PlaybackSlowMotion(Context_t *context, int *speed) playback_err("slowmotion not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); + return ret; } static int32_t PlaybackSeek(Context_t *context, int64_t *pos, uint8_t absolute) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "pos: %lldd\n", *pos); + if (context->playback->isPlaying && !context->playback->isForwarding && !context->playback->BackWard && !context->playback->SlowMotion && !context->playback->isPaused) { context->playback->isSeeking = 1; @@ -576,15 +650,20 @@ static int32_t PlaybackSeek(Context_t *context, int64_t *pos, uint8_t absolute) playback_err("not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); + return ret; } static int32_t PlaybackPts(Context_t *context, int64_t *pts) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(20, "\n"); + *pts = 0; + if (context->playback->isPlaying) { ret = context->output->Command(context, OUTPUT_PTS, pts); @@ -594,15 +673,20 @@ static int32_t PlaybackPts(Context_t *context, int64_t *pts) playback_err("not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(20, "exiting with value %d\n", ret); + return ret; } static int32_t PlaybackGetFrameCount(Context_t *context, uint64_t *frameCount) { int ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(20, "\n"); + *frameCount = 0; + if (context->playback->isPlaying) { ret = context->output->Command(context, OUTPUT_GET_FRAME_COUNT, frameCount); @@ -612,15 +696,20 @@ static int32_t PlaybackGetFrameCount(Context_t *context, uint64_t *frameCount) playback_err("not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(20, "exiting with value %d\n", ret); + return ret; } static int32_t PlaybackLength(Context_t *context, int64_t *length) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(20, "\n"); + *length = -1; + if (context->playback->isPlaying) { if (context->container && context->container->selectedContainer) @@ -633,6 +722,7 @@ static int32_t PlaybackLength(Context_t *context, int64_t *length) playback_err("not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(20, "exiting with value %d\n", ret); return ret; } @@ -642,7 +732,9 @@ static int32_t PlaybackSwitchAudio(Context_t *context, int32_t *track) int32_t ret = cERR_PLAYBACK_NO_ERROR; int32_t curtrackid = 0; int32_t nextrackid = 0; + playback_printf(10, "\n"); + if (context && context->playback && context->playback->isPlaying) { if (context->manager && context->manager->audio) @@ -656,13 +748,16 @@ static int32_t PlaybackSwitchAudio(Context_t *context, int32_t *track) playback_err("switch audio not possible\n"); ret = cERR_PLAYBACK_ERROR; } + if (nextrackid != curtrackid) { + //PlaybackPause(context); if (context->output && context->output->audio) { context->output->audio->Command(context, OUTPUT_SWITCH, (void *)"audio"); } + if (context->container && context->container->selectedContainer) { context->container->selectedContainer->Command(context, CONTAINER_SWITCH_AUDIO, &nextrackid); @@ -675,6 +770,7 @@ static int32_t PlaybackSwitchAudio(Context_t *context, int32_t *track) playback_err("switch audio not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); return ret; } @@ -684,7 +780,9 @@ static int32_t PlaybackSwitchSubtitle(Context_t *context, int32_t *track) int32_t ret = cERR_PLAYBACK_NO_ERROR; int32_t curtrackid = -1; int32_t nextrackid = -1; + playback_printf(10, "Track: %d\n", *track); + if (context && context->playback && context->playback->isPlaying) { if (context->manager && context->manager->subtitle) @@ -692,12 +790,14 @@ static int32_t PlaybackSwitchSubtitle(Context_t *context, int32_t *track) context->manager->subtitle->Command(context, MANAGER_GET, &curtrackid); context->manager->subtitle->Command(context, MANAGER_SET, track); context->manager->subtitle->Command(context, MANAGER_GET, &nextrackid); + if (curtrackid != nextrackid && nextrackid > -1) { if (context->output && context->output->subtitle) { context->output->subtitle->Command(context, OUTPUT_SWITCH, (void *)"subtitle"); } + if (context->container && context->container->selectedContainer) { context->container->selectedContainer->Command(context, CONTAINER_SWITCH_SUBTITLE, &nextrackid); @@ -715,14 +815,18 @@ static int32_t PlaybackSwitchSubtitle(Context_t *context, int32_t *track) playback_err("not possible\n"); ret = cERR_PLAYBACK_ERROR; } + playback_printf(10, "exiting with value %d\n", ret); + return ret; } static int32_t PlaybackInfo(Context_t *context, char **infoString) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(10, "\n"); + /* konfetti comment: * removed if clause here (playback running) because its * not necessary for all container. e.g. in case of ffmpeg @@ -732,7 +836,9 @@ static int32_t PlaybackInfo(Context_t *context, char **infoString) { context->container->selectedContainer->Command(context, CONTAINER_INFO, infoString); } + playback_printf(10, "exiting with value %d\n", ret); + return ret; } @@ -742,13 +848,17 @@ static int PlaybackMetadata(Context_t *context, char ***metadata) if (context->container && context->container->selectedContainer) context->container->selectedContainer->Command(context, CONTAINER_GET_METADATA, metadata); + return ret; } static int32_t Command(Context_t *context, PlaybackCmd_t command, void *argument) { int32_t ret = cERR_PLAYBACK_NO_ERROR; + playback_printf(20, "Command %d\n", command); + + switch (command) { case PLAYBACK_OPEN: @@ -851,7 +961,9 @@ static int32_t Command(Context_t *context, PlaybackCmd_t command, void *argument ret = cERR_PLAYBACK_ERROR; break; } + playback_printf(20, "exiting with value %d\n", ret); + return ret; }