Exemplo n.º 1
0
int Decoder::decode_frame(AVFrame *frame) {
    Decoder *d = this;
    int got_frame = 0;

    do {
        int ret = -1;

        if (d->queue->abort_request)
            return -1;

        if (!d->packet_pending || d->queue->serial != d->pkt_serial) {
            AVPacket pkt;
            do {
                if (d->queue->nb_packets == 0)
                    d->empty_queue_cond ->signal();
                if (d->queue->get(&pkt, 1, &d->pkt_serial) < 0)
                    return -1;
                if (pkt.data == flush_pkt.data) {
                    avcodec_flush_buffers(d->avctx);
                    d->finished = 0;
                    d->next_pts = d->start_pts;
                    d->next_pts_tb = d->start_pts_tb;
                }
            } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
            av_free_packet(&d->pkt);
            d->pkt_temp = d->pkt = pkt;
            d->packet_pending = 1;
        }

        switch (d->avctx->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    if (gOptions.decoder_reorder_pts == -1) {
                        frame->pts = av_frame_get_best_effort_timestamp(frame);
                    } else if (gOptions.decoder_reorder_pts) {
                        frame->pts = frame->pkt_pts;
                    } else {
                        frame->pts = frame->pkt_dts;
                    }
                }
                break;
            case AVMEDIA_TYPE_AUDIO:
                ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    AVRational tb = (AVRational){1, frame->sample_rate};
                    if (frame->pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(frame->pts, d->avctx->time_base, tb);
                    else if (frame->pkt_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb);
                    else if (d->next_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
                    if (frame->pts != AV_NOPTS_VALUE) {
                        d->next_pts = frame->pts + frame->nb_samples;
                        d->next_pts_tb = tb;
                    }
                }
                break;
            case AVMEDIA_TYPE_SUBTITLE:
                {
                    AVSubtitle *sub = (AVSubtitle*) frame;
                    ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp);
                }
                break;
        }

        if (ret < 0) {
            d->packet_pending = 0;
        } else {
            d->pkt_temp.dts =
            d->pkt_temp.pts = AV_NOPTS_VALUE;
            if (d->pkt_temp.data) {
                if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)
                    ret = d->pkt_temp.size;
                d->pkt_temp.data += ret;
                d->pkt_temp.size -= ret;
                if (d->pkt_temp.size <= 0)
                    d->packet_pending = 0;
            } else {
                if (!got_frame) {
                    d->packet_pending = 0;
                    d->finished = d->pkt_serial;
                }
            }
        }
    } while (!got_frame && !d->finished);

    return got_frame;
}
Exemplo n.º 2
0
int Decoder::decodeFrame(AVFrame *frame, AVSubtitle *sub) {
    int got_frame = 0;

    do {
        int ret = -1;
        // 如果处于舍弃状态,则直接返回
        if (queue->isAbort()) {
            return -1;
        }
        // 如果当前没有包在等待,获取队列的序列不相同,取出下一阵
        if (!packet_pending || queue->serial != pkt_serial) {
            AVPacket pkt;
            do {
                // 队列为空
                if (queue->isEmpty()) {
                    CondSignal(empty_queue_cond);
                }
                // 获取裸数据
                if (queue->get(&pkt, 1, &pkt_serial) < 0) {
                    return -1;
                }
                // 刷新数据
                if (pkt.data == flush_pkt->data) {
                    avcodec_flush_buffers(avctx);
                    finished = 0;
                    next_pts = start_pts;
                    next_pts_tb = start_pts_tb;
                }
            } while (pkt.data == flush_pkt->data || queue->serial != pkt_serial);
            av_packet_unref(&this->pkt);
            this->pkt_temp = this->pkt_temp = pkt;
            packet_pending = 1;
        }

        // 根据解码器类型判断是音频还是视频
        switch (avctx->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                // 视频解码
                ret = avcodec_decode_video2(avctx, frame, &got_frame, &pkt_temp);
                // 解码成功,更新时间戳
                if (got_frame) {
                    if (reorderPts == -1) {
                        frame->pts = av_frame_get_best_effort_timestamp(frame);
                    } else if (!reorderPts) {
                        frame->pts = frame->pkt_dts;
                    }
                }
                break;

            case AVMEDIA_TYPE_AUDIO:
                // 音频解码
                ret = avcodec_decode_audio4(avctx, frame, &got_frame, &pkt_temp);
                if (got_frame) {
                    AVRational tb = (AVRational) {1, frame->sample_rate};
                    // 更新帧时间戳
                    if (frame->pts != AV_NOPTS_VALUE) {
                        frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(avctx), tb);
                    } else if (next_pts != AV_NOPTS_VALUE) {
                        frame->pts = av_rescale_q(next_pts, next_pts_tb, tb);
                    }
                    // 更新下一帧时间戳
                    if (frame->pts != AV_NOPTS_VALUE) {
                        next_pts = frame->pts + frame->nb_samples;
                        next_pts_tb = tb;
                    }
                }
                break;
        }

        // 判断是否解码成功
        if (ret < 0) {
            packet_pending = 0;
        } else {
            pkt_temp.dts = pkt_temp.pts = AV_NOPTS_VALUE;
            if (pkt_temp.data) {
                if (avctx->codec_type != AVMEDIA_TYPE_AUDIO) {
                    ret = pkt_temp.size;
                }
                pkt_temp.data += ret;
                pkt_temp.size -= ret;

                if (pkt_temp.size <= 0) {
                    packet_pending = 0;
                }
            } else {
                if (!got_frame) {
                    packet_pending = 0;
                    finished = pkt_serial;
                }
            }
        }
    } while (!got_frame && !finished);

    return got_frame;
}