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 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) { ffmpeg_err("context3 alloc for stream %d failed\n", (int)stream->id); return NULL; } if (avcodec_parameters_to_context(avCodecCtx, stream->codecpar) < 0) { ffmpeg_err("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 int64_t ffmpeg_seek(void *opaque, 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=%lld\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=%lld\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=%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; }
//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__); } } } } }