|
@@ -81,9 +81,6 @@ static int av_decode(struct DecoderContext *pContext, AVPacket *pPacket, enum AV
|
|
|
av_frame_free(&out_frame);
|
|
|
break;
|
|
|
}
|
|
|
- if (pContext->frame_count > 0 && pContext->decode_frame_count >= pContext->frame_count)break;
|
|
|
-
|
|
|
- pContext->decode_frame_count += 1;
|
|
|
|
|
|
int64_t pts = -1;
|
|
|
if (pPacket)
|
|
@@ -92,6 +89,24 @@ static int av_decode(struct DecoderContext *pContext, AVPacket *pPacket, enum AV
|
|
|
else
|
|
|
pts = out_frame->pts * (1000 *
|
|
|
(av_q2d(pContext->avformatContext->streams[pContext->st_index[type]]->time_base)));
|
|
|
+ if (pContext->end_time > 0 && pts >= pContext->end_time)break;
|
|
|
+
|
|
|
+// LOGE("decode is video=%d pts=%lld \n",pPacket->stream_index == pContext->st_index[AVMEDIA_TYPE_VIDEO],pts);
|
|
|
+ if (pts < pContext->start_time && pContext->start_time >= 0 && pContext->force_Iframe != 1) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ double def_frame_delay =
|
|
|
+ (double) (1000.0 / pContext->fps);
|
|
|
+ //如果持续时间很短,那么就用每帧固定延迟时间
|
|
|
+ if (out_frame->pkt_duration < 10) {
|
|
|
+ pContext->decode_frame_ms += (long) def_frame_delay;
|
|
|
+ } else {//使用更加精准的帧延迟时间
|
|
|
+ //根据每帧的延迟时间来相加,更加精准,有些 pkt_duration 持续时长是 0
|
|
|
+ pContext->decode_frame_ms += (int64_t) (out_frame->pkt_duration *
|
|
|
+ ((AV_TIME_BASE *
|
|
|
+ (av_q2d(pContext->avformatContext->streams[pContext->st_index[AVMEDIA_TYPE_VIDEO]]->time_base)))))/1000;
|
|
|
+ }
|
|
|
|
|
|
out_frame->pts = pts;
|
|
|
out_frame->pkt_dts = pts;
|
|
@@ -112,10 +127,10 @@ static int av_decode(struct DecoderContext *pContext, AVPacket *pPacket, enum AV
|
|
|
* @param url
|
|
|
* @param outVideoFormat
|
|
|
* @param force_Iframe
|
|
|
- * @param decode_frame_count
|
|
|
+ * @param end_time
|
|
|
* @return
|
|
|
*/
|
|
|
-long initDecoder(const char *url, int force_Iframe, int decode_frame_count, DisableMediaType disableMediaType) {
|
|
|
+long initDecoder(const char *url, int force_Iframe, long start_time, int end_time, DisableMediaType disableMediaType) {
|
|
|
struct DecoderContext *dctx = (struct DecoderContext *) malloc(sizeof(struct DecoderContext));
|
|
|
if (!dctx) {
|
|
|
LOGE("DecoderContext create fail.");
|
|
@@ -124,8 +139,9 @@ long initDecoder(const char *url, int force_Iframe, int decode_frame_count, Disa
|
|
|
memset(dctx, 0, sizeof(struct DecoderContext));
|
|
|
dctx->url = strdup(url);
|
|
|
dctx->force_Iframe = force_Iframe;
|
|
|
- dctx->frame_count = decode_frame_count;
|
|
|
- dctx->ffthread_count = 3;
|
|
|
+ dctx->ffthread_count = 0;
|
|
|
+ dctx->start_time = start_time;
|
|
|
+ dctx->end_time = end_time;
|
|
|
dctx->disableType = disableMediaType;
|
|
|
char err_info[512] = {0};
|
|
|
int ret = avformat_open_input(&(dctx->avformatContext), dctx->url, NULL, NULL);
|
|
@@ -148,11 +164,26 @@ long initDecoder(const char *url, int force_Iframe, int decode_frame_count, Disa
|
|
|
dctx->st_index[AVMEDIA_TYPE_VIDEO] =
|
|
|
av_find_best_stream(dctx->avformatContext, AVMEDIA_TYPE_VIDEO,
|
|
|
dctx->st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
|
|
|
+ if (dctx->st_index[AVMEDIA_TYPE_VIDEO] < 0) {
|
|
|
+ for (int i = 0; i < dctx->avformatContext->nb_streams; ++i) {
|
|
|
+ if (dctx->avformatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
|
|
|
+ dctx->st_index[AVMEDIA_TYPE_VIDEO] = i;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
dctx->st_index[AVMEDIA_TYPE_AUDIO] = av_find_best_stream(dctx->avformatContext,
|
|
|
AVMEDIA_TYPE_AUDIO,
|
|
|
-1,
|
|
|
-1,
|
|
|
NULL, 0);
|
|
|
+
|
|
|
+ if (dctx->st_index[AVMEDIA_TYPE_AUDIO] < 0) {
|
|
|
+ for (int i = 0; i < dctx->avformatContext->nb_streams; ++i) {
|
|
|
+ if (dctx->avformatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
|
|
+ dctx->st_index[AVMEDIA_TYPE_AUDIO] = i;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
if (dctx->st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
|
|
|
AVStream *as = dctx->avformatContext->streams[dctx->st_index[AVMEDIA_TYPE_VIDEO]];
|
|
|
dctx->v_codec_id = as->codecpar->codec_id;
|
|
@@ -188,8 +219,12 @@ long initDecoder(const char *url, int force_Iframe, int decode_frame_count, Disa
|
|
|
|
|
|
}
|
|
|
dctx->totalMs = dctx->avformatContext->duration / (AV_TIME_BASE / 1000);
|
|
|
- LOGE("媒体总时长 totalMs=%lld \n", dctx->totalMs);
|
|
|
+ if (dctx->start_time > dctx->totalMs) {
|
|
|
+ LOGE("媒体总时长 totalMs=%lld start_time=%lld \n", dctx->totalMs, dctx->start_time);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
+ LOGE("媒体总时长 totalMs=%lld \n", dctx->totalMs);
|
|
|
if (dctx->avformatContext->start_time != AV_NOPTS_VALUE)
|
|
|
dctx->offset = dctx->avformatContext->start_time;
|
|
|
|
|
@@ -221,7 +256,7 @@ long initDecoder(const char *url, int force_Iframe, int decode_frame_count, Disa
|
|
|
dctx->video_queue = new BlockQueue<AVFrame *>(dctx->fps);
|
|
|
}
|
|
|
|
|
|
- int64_t timestamp = 0;
|
|
|
+ int64_t timestamp = dctx->start_time * 1000;
|
|
|
if (dctx->offset != AV_NOPTS_VALUE)
|
|
|
timestamp += dctx->offset;
|
|
|
if (timestamp > 0) {
|
|
@@ -307,7 +342,7 @@ void *av_read_decode_thread(void *pVoid) {
|
|
|
struct DecoderContext *ctx = (struct DecoderContext *) pVoid;
|
|
|
if (ctx && ctx->avformatContext) {
|
|
|
while (1) {
|
|
|
- if (ctx->decode_frame_count > ctx->frame_count && ctx->frame_count > 0)
|
|
|
+ if (ctx->decode_frame_ms > ctx->end_time && ctx->end_time > 0)
|
|
|
break;
|
|
|
AVPacket *pkg = av_packet_alloc();
|
|
|
ret = av_read_frame(ctx->avformatContext, pkg);
|