mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 15:02:58 +02:00
lib cleanup and sync for mips vu support
This commit is contained in:
673
libeplayer3/container/buff_ffmpeg.c
Normal file
673
libeplayer3/container/buff_ffmpeg.c
Normal file
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* Container handling for all stream's handled by ffmpeg
|
||||
* konfetti 2010; based on code from crow
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#define FILLBUFSIZE 0
|
||||
#define FILLBUFDIFF 1048576
|
||||
#define FILLBUFPAKET 5120
|
||||
#define FILLBUFSEEKTIME 3 //sec
|
||||
#define TIMEOUT_MAX_ITERS 10
|
||||
|
||||
static int ffmpeg_buf_size = FILLBUFSIZE + FILLBUFDIFF;
|
||||
static int ffmpeg_buf_seek_time = FILLBUFSEEKTIME;
|
||||
static int(*ffmpeg_read_org)(void *opaque, uint8_t *buf, int buf_size) = NULL;
|
||||
static int(*ffmpeg_real_read_org)(void *opaque, uint8_t *buf, int buf_size) = NULL;
|
||||
|
||||
static int64_t(*ffmpeg_seek_org)(void *opaque, int64_t offset, int whence) = NULL;
|
||||
static unsigned char *ffmpeg_buf_read = NULL;
|
||||
static unsigned char *ffmpeg_buf_write = NULL;
|
||||
static unsigned char *ffmpeg_buf = NULL;
|
||||
static pthread_t fillerThread;
|
||||
static int hasfillerThreadStarted[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int hasfillerThreadStartedID = 0;
|
||||
static pthread_mutex_t fillermutex;
|
||||
static int ffmpeg_buf_valid_size = 0;
|
||||
static int ffmpeg_do_seek_ret = 0;
|
||||
static int ffmpeg_do_seek = 0;
|
||||
static int ffmpeg_buf_stop = 0;
|
||||
|
||||
static Context_t *g_context = 0;
|
||||
static int64_t playPts = -1;
|
||||
static int32_t finishTimeout = 0;
|
||||
static int8_t pauseTimeout = 0;
|
||||
static int64_t maxInjectedPTS = INVALID_PTS_VALUE;
|
||||
|
||||
static int64_t update_max_injected_pts(int64_t pts)
|
||||
{
|
||||
if (pts > 0 && pts != INVALID_PTS_VALUE)
|
||||
{
|
||||
if (maxInjectedPTS == INVALID_PTS_VALUE || pts > maxInjectedPTS || 0 == PlaybackDieNow(0))
|
||||
{
|
||||
maxInjectedPTS = pts;
|
||||
}
|
||||
}
|
||||
return maxInjectedPTS;
|
||||
}
|
||||
|
||||
int64_t get_play_pts()
|
||||
{
|
||||
return playPts;
|
||||
}
|
||||
|
||||
void reset_finish_timeout()
|
||||
{
|
||||
playPts = -1;
|
||||
finishTimeout = 0;
|
||||
}
|
||||
|
||||
void set_pause_timeout(uint8_t pause)
|
||||
{
|
||||
reset_finish_timeout();
|
||||
pauseTimeout = pause;
|
||||
}
|
||||
|
||||
static int8_t is_finish_timeout()
|
||||
{
|
||||
if (finishTimeout > TIMEOUT_MAX_ITERS)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_finish_timeout()
|
||||
{
|
||||
if (0 == pauseTimeout)
|
||||
{
|
||||
int64_t maxInjectedPts = update_max_injected_pts(-1);
|
||||
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[%" PRId64 "] currPts[%" PRId64 "] maxInjectedPts[%" PRId64 "]\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)
|
||||
{
|
||||
/* close immediately
|
||||
*/
|
||||
finishTimeout = TIMEOUT_MAX_ITERS + 1;
|
||||
}
|
||||
else if (0 == ret && (playPts != currPts && maxInjectedPts > currPts))
|
||||
{
|
||||
playPts = currPts;
|
||||
finishTimeout = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t ffmpeg_read_wrapper_base(void *opaque, uint8_t *buf, int32_t buf_size, uint8_t type)
|
||||
{
|
||||
int32_t len = 0;
|
||||
if (0 == PlaybackDieNow(0))
|
||||
{
|
||||
len = ffmpeg_real_read_org(opaque, buf, buf_size);
|
||||
while (len < buf_size && g_context && 0 == PlaybackDieNow(0))
|
||||
{
|
||||
if (type && len > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t partLen = ffmpeg_real_read_org(opaque, buf + len, buf_size - len);
|
||||
if (partLen > 0)
|
||||
{
|
||||
len += partLen;
|
||||
finishTimeout = 0;
|
||||
continue;
|
||||
}
|
||||
else if (is_finish_timeout())
|
||||
{
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
update_finish_timeout();
|
||||
|
||||
usleep(100000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//printf("len [%d] finishTimeout[%d]\n", len, finishTimeout);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int32_t ffmpeg_read_wrapper(void *opaque, uint8_t *buf, int32_t buf_size)
|
||||
{
|
||||
if (progressive_playback)
|
||||
{
|
||||
return ffmpeg_read_wrapper_base(opaque, buf, buf_size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* at start it was progressive playback, but dwonload, finished
|
||||
*/
|
||||
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 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)
|
||||
{
|
||||
ffmpeg_buf_seek_time = (*time);
|
||||
return cERR_CONTAINER_FFMPEG_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int32_t container_set_ffmpeg_buf_size(int32_t *size)
|
||||
{
|
||||
if (ffmpeg_buf == NULL)
|
||||
{
|
||||
if (*size == 0)
|
||||
{
|
||||
ffmpeg_buf_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffmpeg_buf_size = (*size) + FILLBUFDIFF;
|
||||
}
|
||||
}
|
||||
|
||||
ffmpeg_printf(10, "size=%d, buffer size=%d\n", (*size), ffmpeg_buf_size);
|
||||
return cERR_CONTAINER_FFMPEG_NO_ERROR;
|
||||
}
|
||||
|
||||
static int32_t container_get_ffmpeg_buf_size(int32_t *size)
|
||||
{
|
||||
*size = ffmpeg_buf_size - FILLBUFDIFF;
|
||||
return cERR_CONTAINER_FFMPEG_NO_ERROR;
|
||||
}
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
*size = rwdiff;
|
||||
}
|
||||
|
||||
return cERR_CONTAINER_FFMPEG_NO_ERROR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int32_t container_stop_buffer()
|
||||
{
|
||||
ffmpeg_buf_stop = 1;
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (0 == PlaybackDieNow(0))
|
||||
{
|
||||
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)
|
||||
{
|
||||
ffmpeg_do_seek_ret = ffmpeg_seek_org(avContextTab[0]->pb->opaque, avContextTab[0]->pb->pos + ffmpeg_do_seek, SEEK_SET);
|
||||
if (ffmpeg_do_seek_ret >= 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
memcpy(ffmpeg_buf_write, buf, len);
|
||||
ffmpeg_buf_write += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
|
||||
ffmpeg_err("read not ok ret=%d\n", len);
|
||||
break;
|
||||
}
|
||||
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
//on long pause the server close the connection, so we use seek to reconnect
|
||||
if (context != NULL && context->playback != NULL && inpause != NULL)
|
||||
{
|
||||
if ((*inpause) == 0 && context->playback->isPaused)
|
||||
{
|
||||
(*inpause) = 1;
|
||||
}
|
||||
else if ((*inpause) == 1 && !context->playback->isPaused)
|
||||
{
|
||||
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;
|
||||
buflen += ffmpeg_buf_write - ffmpeg_buf;
|
||||
}
|
||||
ffmpeg_seek_org(avContextTab[0]->pb->opaque, avContextTab[0]->pb->pos + buflen, SEEK_SET);
|
||||
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
else
|
||||
{
|
||||
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++)
|
||||
{
|
||||
if (hasfillerThreadStarted[i] == 0)
|
||||
{
|
||||
hasfillerThreadStartedID = i;
|
||||
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
|
||||
{
|
||||
ffmpeg_printf(10, "Created filler thread\n");
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static int32_t ffmpeg_read_real(void *opaque __attribute__((unused)), uint8_t *buf, int32_t buf_size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read;
|
||||
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)
|
||||
{
|
||||
ffmpeg_buf_valid_size = FILLBUFDIFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffmpeg_buf_valid_size += len;
|
||||
}
|
||||
}
|
||||
|
||||
if (ffmpeg_buf_read == ffmpeg_buf + ffmpeg_buf_size)
|
||||
{
|
||||
ffmpeg_buf_read = ffmpeg_buf;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
len = 0;
|
||||
}
|
||||
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
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);
|
||||
sumlen += len;
|
||||
buf += len;
|
||||
if (len == 0)
|
||||
{
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
if (sumlen == 0)
|
||||
{
|
||||
ffmpeg_err("Timeout waiting for buffered data (buf_size=%d sumlen=%d)!\n", buf_size, sumlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffmpeg_err("Timeout, not all buffered data availabel (buf_size=%d sumlen=%d)!\n", buf_size, sumlen);
|
||||
}
|
||||
}
|
||||
|
||||
return sumlen;
|
||||
}
|
||||
|
||||
static int64_t ffmpeg_seek(void *opaque __attribute__((unused)), int64_t offset, int32_t whence)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 */
|
||||
ffmpeg_printf(20, "buffer-seek diff=%" PRId64 "\n", diff);
|
||||
if (diff > (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read)
|
||||
{
|
||||
ffmpeg_buf_read = ffmpeg_buf + (diff - ((ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read));
|
||||
}
|
||||
else
|
||||
{
|
||||
ffmpeg_buf_read = ffmpeg_buf_read + diff;
|
||||
}
|
||||
}
|
||||
else if (diff < 0 && diff * -1 < ffmpeg_buf_valid_size)
|
||||
{
|
||||
/* can do the seek inside the buffer */
|
||||
ffmpeg_printf(20, "buffer-seek diff=%" PRId64 "\n", diff);
|
||||
int32_t tmpdiff = diff * -1;
|
||||
if (tmpdiff > ffmpeg_buf_read - ffmpeg_buf)
|
||||
{
|
||||
ffmpeg_buf_read = (ffmpeg_buf + ffmpeg_buf_size) - (tmpdiff - (ffmpeg_buf_read - ffmpeg_buf));
|
||||
}
|
||||
else
|
||||
{
|
||||
ffmpeg_buf_read = ffmpeg_buf_read - tmpdiff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
|
||||
ffmpeg_printf(20, "real-seek diff=%" PRId64 "\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;
|
||||
}
|
||||
|
||||
static void ffmpeg_buf_free()
|
||||
{
|
||||
ffmpeg_read_org = NULL;
|
||||
ffmpeg_seek_org = NULL;
|
||||
ffmpeg_buf_read = NULL;
|
||||
ffmpeg_buf_write = NULL;
|
||||
free(ffmpeg_buf);
|
||||
ffmpeg_buf = NULL;
|
||||
ffmpeg_buf_valid_size = 0;
|
||||
ffmpeg_do_seek_ret = 0;
|
||||
ffmpeg_do_seek = 0;
|
||||
ffmpeg_buf_stop = 0;
|
||||
hasfillerThreadStartedID = 0;
|
||||
}
|
126
libeplayer3/container/container.c
Normal file
126
libeplayer3/container/container.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Main Container Handling.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
|
||||
static Container_t *AvailableContainer[] =
|
||||
{
|
||||
&FFMPEGContainer,
|
||||
NULL
|
||||
};
|
||||
|
||||
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++)
|
||||
{
|
||||
container_printf(10, "%s ", AvailableContainer[i]->Capabilities[j]);
|
||||
}
|
||||
}
|
||||
container_printf(10, "\n");
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
case CONTAINER_ADD:
|
||||
{
|
||||
ret = selectContainer(context, (char *) argument);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_CAPABILITIES:
|
||||
{
|
||||
printContainerCapabilities();
|
||||
break;
|
||||
}
|
||||
case CONTAINER_DEL:
|
||||
{
|
||||
context->container->selectedContainer = NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
container_err("%s::%s ContainerCmd %d not supported!\n", __FILE__, __FUNCTION__, command);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ContainerHandler_t ContainerHandler =
|
||||
{
|
||||
"Output",
|
||||
NULL,
|
||||
Command
|
||||
};
|
3404
libeplayer3/container/container_ffmpeg.c
Normal file
3404
libeplayer3/container/container_ffmpeg.c
Normal file
File diff suppressed because it is too large
Load Diff
95
libeplayer3/container/flv2mpeg4_ffmpeg.c
Normal file
95
libeplayer3/container/flv2mpeg4_ffmpeg.c
Normal file
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// more info
|
||||
// http://forum.doom9.org/archive/index.php/t-157998.html
|
||||
//
|
||||
|
||||
#include "flv2mpeg4/flv2mpeg4.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
flv2mpeg4_CTX *ctx;
|
||||
uint8_t *extradata;
|
||||
int extradatasize;
|
||||
|
||||
Context_t *out_ctx;
|
||||
Track_t *track;
|
||||
} Flv2Mpeg4Context;
|
||||
|
||||
|
||||
static int flv2mpeg4_context_write_packet_cb(void *usr_data, int keyframe __attribute__((unused)), int pts __attribute__((unused)), const uint8_t *buf, int size)
|
||||
{
|
||||
Flv2Mpeg4Context *ctx = usr_data;
|
||||
if (!ctx)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
AudioVideoOut_t avOut;
|
||||
avOut.data = (char *)buf;
|
||||
avOut.len = size;
|
||||
avOut.pts = ctx->track->pts;
|
||||
avOut.dts = ctx->track->dts;
|
||||
avOut.extradata = ctx->extradata;
|
||||
avOut.extralen = ctx->extradatasize;
|
||||
avOut.frameRate = ctx->track->frame_rate;
|
||||
avOut.timeScale = ctx->track->TimeScale;
|
||||
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;
|
||||
}
|
||||
|
||||
static int flv2mpeg4_context_write_extradata_cb(void *usr_data, int width __attribute__((unused)), int height __attribute__((unused)), int bitrate __attribute__((unused)), const uint8_t *extradata, int extradatasize)
|
||||
{
|
||||
Flv2Mpeg4Context *ctx = usr_data;
|
||||
if (!ctx)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(ctx->extradata);
|
||||
ctx->extradata = malloc(extradatasize);
|
||||
memcpy(ctx->extradata, extradata, extradatasize);
|
||||
ctx->extradatasize = extradatasize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flv2mpeg4_context_reset(Flv2Mpeg4Context *context)
|
||||
{
|
||||
if (context == NULL || context->ctx == NULL)
|
||||
return;
|
||||
|
||||
flv2mpeg4_set_frame(context->ctx, 0, 0);
|
||||
}
|
||||
|
||||
static int flv2mpeg4_write_packet(Context_t *out_ctx, Flv2Mpeg4Context *mpeg4p2_ctx, Track_t *track, int cAVIdx, int64_t *pts_current, int64_t *pts_latest, AVPacket *pkt)
|
||||
{
|
||||
if (!mpeg4p2_ctx->ctx)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
144
libeplayer3/container/mpeg4p2_ffmpeg.c
Executable file
144
libeplayer3/container/mpeg4p2_ffmpeg.c
Executable file
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// mpeg4-part2 in mipsel receivers
|
||||
// http://forums.openpli.org/topic/39326-gstreamer10-and-mpeg4-part2/?hl=%2Bmpeg4+%2Bpart2
|
||||
//
|
||||
|
||||
// mpeg4_unpack_bframes
|
||||
typedef struct
|
||||
{
|
||||
const AVBitStreamFilter *bsf;
|
||||
AVBSFContext *ctx;
|
||||
} Mpeg4P2Context;
|
||||
|
||||
static Mpeg4P2Context *mpeg4p2_context_open()
|
||||
{
|
||||
Mpeg4P2Context *context = NULL;
|
||||
const AVBitStreamFilter *bsf = av_bsf_get_by_name("mpeg4_unpack_bframes");
|
||||
if (bsf)
|
||||
{
|
||||
context = malloc(sizeof(Mpeg4P2Context));
|
||||
if (context)
|
||||
{
|
||||
memset(context, 0x00, sizeof(Mpeg4P2Context));
|
||||
context->bsf = bsf;
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
static void mpeg4p2_write(Context_t *ctx, Mpeg4P2Context *mpeg4p2_ctx, Track_t *track, int64_t start_time, int64_t *currentVideoPts, int64_t *latest_Pts, AVPacket *pkt)
|
||||
{
|
||||
*currentVideoPts = track->pts = doCalcPts(start_time, mpeg4p2_ctx->ctx->time_base_out, pkt->pts);
|
||||
if ((*currentVideoPts > *latest_Pts) && (*currentVideoPts != INVALID_PTS_VALUE))
|
||||
{
|
||||
*latest_Pts = *currentVideoPts;
|
||||
}
|
||||
|
||||
track->dts = doCalcPts(start_time, mpeg4p2_ctx->ctx->time_base_out, pkt->dts);
|
||||
|
||||
AudioVideoOut_t avOut;
|
||||
avOut.data = pkt->data;
|
||||
avOut.len = pkt->size;
|
||||
avOut.pts = track->pts;
|
||||
avOut.dts = track->dts;
|
||||
avOut.extradata = mpeg4p2_ctx->ctx->par_out->extradata;
|
||||
avOut.extralen = mpeg4p2_ctx->ctx->par_out->extradata_size;
|
||||
avOut.frameRate = track->frame_rate;
|
||||
avOut.timeScale = track->TimeScale;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
static int mpeg4p2_context_reset(Mpeg4P2Context *context)
|
||||
{
|
||||
int ret = 0;
|
||||
if (context && context->ctx)
|
||||
{
|
||||
// Flush
|
||||
ret = av_bsf_send_packet(context->ctx, NULL);
|
||||
if (ret == 0)
|
||||
{
|
||||
AVPacket *pkt = NULL;
|
||||
while ((ret = av_bsf_receive_packet(context->ctx, pkt)) == 0)
|
||||
{
|
||||
wrapped_frame_unref(pkt);
|
||||
}
|
||||
}
|
||||
av_bsf_free(&context->ctx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpeg4p2_write_packet(Context_t *ctx, Mpeg4P2Context *mpeg4p2_ctx, Track_t *track, int cAVIdx, int64_t *pts_current, int64_t *pts_latest, AVPacket *pkt)
|
||||
{
|
||||
int ret = 0;
|
||||
if (mpeg4p2_ctx)
|
||||
{
|
||||
// Setup is needed
|
||||
if (!mpeg4p2_ctx->ctx)
|
||||
{
|
||||
ret = av_bsf_alloc(mpeg4p2_ctx->bsf, &mpeg4p2_ctx->ctx);
|
||||
if (ret == 0)
|
||||
{
|
||||
AVStream *in = track->stream;
|
||||
ret = avcodec_parameters_copy(mpeg4p2_ctx->ctx->par_in, in->codecpar);
|
||||
if (ret == 0)
|
||||
{
|
||||
mpeg4p2_ctx->ctx->time_base_in = in->time_base;
|
||||
ret = av_bsf_init(mpeg4p2_ctx->ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = av_bsf_send_packet(mpeg4p2_ctx->ctx, pkt);
|
||||
if (ret == 0)
|
||||
{
|
||||
while ((ret = av_bsf_receive_packet(mpeg4p2_ctx->ctx, pkt)) == 0)
|
||||
{
|
||||
mpeg4p2_write(ctx, mpeg4p2_ctx, track, avContextTab[cAVIdx]->start_time, pts_current, pts_latest, pkt);
|
||||
}
|
||||
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
ffmpeg_err("av_bsf_receive_packet failed error 0x%x\n", ret);
|
||||
mpeg4p2_context_reset(mpeg4p2_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ffmpeg_err("bsf setup failed error 0x%x\n", ret);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mpeg4p2_context_close(Mpeg4P2Context *context)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
mpeg4p2_context_reset(context);
|
||||
free(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
211
libeplayer3/container/wrapped_ffmpeg.c
Normal file
211
libeplayer3/container/wrapped_ffmpeg.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Wrapper functions for FFMPEG API which
|
||||
* allows to compile and use exteplayer3
|
||||
* with old ffmpeg libs
|
||||
*/
|
||||
static void wrapped_frame_free(void *param)
|
||||
{
|
||||
#if (LIBAVCODEC_VERSION_MAJOR >= 55)
|
||||
av_frame_free(param);
|
||||
#else
|
||||
avcodec_free_frame(param);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *wrapped_frame_alloc()
|
||||
{
|
||||
#if (LIBAVCODEC_VERSION_MAJOR >= 55)
|
||||
return av_frame_alloc();
|
||||
#else
|
||||
return avcodec_alloc_frame();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wrapped_frame_unref(void *param)
|
||||
{
|
||||
#if (LIBAVCODEC_VERSION_MAJOR >= 55)
|
||||
av_frame_unref(param);
|
||||
#else
|
||||
avcodec_get_frame_defaults(param);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wrapped_packet_unref(void *param)
|
||||
{
|
||||
#if (LIBAVCODEC_VERSION_MAJOR > 55)
|
||||
av_packet_unref(param);
|
||||
#else
|
||||
av_free_packet(param);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wrapped_set_max_analyze_duration(void *param, int val __attribute__((unused)))
|
||||
{
|
||||
#if (LIBAVFORMAT_VERSION_MAJOR > 55) && (LIBAVFORMAT_VERSION_MAJOR < 56)
|
||||
((AVFormatContext *)param)->max_analyze_duration2 = val;
|
||||
#else
|
||||
((AVFormatContext *)param)->max_analyze_duration = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t get_packet_duration(AVPacket *packet)
|
||||
{
|
||||
#if LIBAVFORMAT_VERSION_MAJOR > 56
|
||||
return packet->duration;
|
||||
#else
|
||||
return packet->convergence_duration;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
|
||||
static AVCodecParameters *get_codecpar(AVStream *stream)
|
||||
{
|
||||
return stream->codecpar;
|
||||
}
|
||||
#else
|
||||
static AVCodecContext *get_codecpar(AVStream *stream)
|
||||
{
|
||||
return stream->codec;
|
||||
}
|
||||
#endif
|
||||
|
||||
static AVRational get_frame_rate(AVStream *stream)
|
||||
{
|
||||
AVRational rateRational = stream->avg_frame_rate;
|
||||
if (0 == rateRational.den)
|
||||
{
|
||||
rateRational = stream->r_frame_rate;
|
||||
}
|
||||
return rateRational;
|
||||
}
|
||||
|
||||
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
|
||||
typedef struct CodecCtxStoreItem_s
|
||||
{
|
||||
uint32_t cAVIdx;
|
||||
int id;
|
||||
AVCodecContext *avCodecCtx;
|
||||
void *next;
|
||||
} CodecCtxStoreItem_t;
|
||||
|
||||
static CodecCtxStoreItem_t *g_codecCtxStoreListHead = NULL;
|
||||
|
||||
AVCodecContext *restore_avcodec_context(uint32_t cAVIdx, int32_t id)
|
||||
{
|
||||
CodecCtxStoreItem_t *ptr = g_codecCtxStoreListHead;
|
||||
while (ptr != NULL)
|
||||
{
|
||||
if (ptr->cAVIdx == cAVIdx && ptr->id == id)
|
||||
{
|
||||
return ptr->avCodecCtx;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_all_stored_avcodec_context()
|
||||
{
|
||||
while (g_codecCtxStoreListHead != NULL)
|
||||
{
|
||||
CodecCtxStoreItem_t *ptr = g_codecCtxStoreListHead->next;
|
||||
free(g_codecCtxStoreListHead);
|
||||
g_codecCtxStoreListHead = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
int store_avcodec_context(AVCodecContext *avCodecCtx __attribute__((unused)), uint32_t cAVIdx __attribute__((unused)), int id __attribute__((unused)))
|
||||
{
|
||||
CodecCtxStoreItem_t *ptr = malloc(sizeof(CodecCtxStoreItem_t));
|
||||
if (!ptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(ptr, 0x00, sizeof(CodecCtxStoreItem_t));
|
||||
ptr->next = g_codecCtxStoreListHead;
|
||||
g_codecCtxStoreListHead = ptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
void free_all_stored_avcodec_context()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static AVCodecContext *wrapped_avcodec_get_context(uint32_t cAVIdx, AVStream *stream)
|
||||
{
|
||||
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
|
||||
AVCodecContext *avCodecCtx = restore_avcodec_context(cAVIdx, stream->id);
|
||||
if (!avCodecCtx)
|
||||
{
|
||||
avCodecCtx = avcodec_alloc_context3(NULL);
|
||||
if (!avCodecCtx)
|
||||
{
|
||||
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);
|
||||
avcodec_free_context(&avCodecCtx);
|
||||
return NULL;
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
av_codec_set_pkt_timebase(avCodecCtx, stream->time_base);
|
||||
#else
|
||||
avCodecCtx->pkt_timebase = stream->time_base;
|
||||
#endif
|
||||
store_avcodec_context(avCodecCtx, cAVIdx, stream->id);
|
||||
}
|
||||
|
||||
return avCodecCtx;
|
||||
#else
|
||||
return stream->codec;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wrapped_avcodec_flush_buffers(uint32_t cAVIdx)
|
||||
{
|
||||
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
|
||||
CodecCtxStoreItem_t *ptr = g_codecCtxStoreListHead;
|
||||
while (ptr != NULL)
|
||||
{
|
||||
if (ptr->cAVIdx == cAVIdx && ptr->avCodecCtx && ptr->avCodecCtx->codec)
|
||||
{
|
||||
avcodec_flush_buffers(ptr->avCodecCtx);
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
#else
|
||||
uint32_t j;
|
||||
for (j = 0; j < avContextTab[cAVIdx]->nb_streams; j++)
|
||||
{
|
||||
if (avContextTab[cAVIdx]->streams[j]->codec && avContextTab[cAVIdx]->streams[j]->codec->codec)
|
||||
{
|
||||
avcodec_flush_buffers(avContextTab[cAVIdx]->streams[j]->codec);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wrapped_register_all(void)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
avcodec_register_all();
|
||||
av_register_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t wrapped_frame_get_best_effort_timestamp(const AVFrame *frame)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
return av_frame_get_best_effort_timestamp(frame);
|
||||
#else
|
||||
return frame->best_effort_timestamp;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user