溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

FFmpeg Reinit context to 1920x1088問題描述

發(fā)布時(shí)間:2020-06-12 10:28:33 來源:網(wǎng)絡(luò) 閱讀:2453 作者:fengyuzaitu 欄目:編程語言
場景
    指定??禂z像機(jī)的分辨率是1920*1080P,I幀間隔是25,視頻幀率是25fps。查看AVFormatContext結(jié)構(gòu)體中streams數(shù)組中的第一個(gè)元素codec
    codec_id=AV_CODEC_ID_H264, width=1920, height=1080, coded_with=1920, coded_height=1088, pix_fmt=AV_PIX_FMT_YUVJ420P

疑問
    coded_height為什么不是1080

解答
當(dāng)前SPS的幀的寬 = (sps_info.pic_width_in_mbs_minus1 + 1) * 16
當(dāng)前SPS的幀的高 = (sps_info.pic_height_in_map_units_minus1 + 1) * 16
通過如下代碼計(jì)算得到的寬高(1888 x 1920)卻不完全等同于源視頻的寬高(1920 x 1080)。
根據(jù)編碼規(guī)則計(jì)算到的寬高是1920x1088,而MP4中讀取的是1920x1080。那么,如何FFmpeg是如何修正SPS里的寬高計(jì)算呢?
實(shí)際上,SPS還有crop系列字段,由crop表示幀是否被裁剪、crop_left、crop_right、crop_top和crop_bottom表示要裁剪的值得到正確的寬高值。


相關(guān)知識
sps和pps的結(jié)構(gòu)參考:h364編碼 里面的Sequence parameter set RBSP syntax
0x00000001或者0x000001是起始碼,0x67是sps的開頭,0x68是pps的開頭。
0x42代表profile_idc,后面八位是constraint_set0_flag和reserved_zero_4bits,都設(shè)為0,0x0a是level_idc,
接著后面為圖方便能用0表示的都用了。這里要注意是ue(v)表示該域是可變位,使用的指數(shù)-哥倫布編碼
我的目的主要是設(shè)置正確幀高度和幀高度,所以只要填充   pic_width_in_mbs_minus1和  pic_height_in_map_units_minus1,
將它們的十六進(jìn)制數(shù)寫入sps_pps,
如果寬度和高度不是16的倍數(shù),要填frame_cropping_flag

參考
http://m.blog.csdn.net/stn_lcd/article/details/74390636
http://m.blog.csdn.net/leixiaohua1020/article/details/45001033

static int h364_init_ps(H264Context *h, const H264SliceContext *sl, int first_slice)
{
    const SPS *sps;
    int needs_reinit = 0, must_reinit, ret;

    if (first_slice) {
        av_buffer_unref(&h->ps.pps_ref);
        h->ps.pps = NULL;
        h->ps.pps_ref = av_buffer_ref(h->ps.pps_list[sl->pps_id]);
        if (!h->ps.pps_ref)
            return AVERROR(ENOMEM);
        h->ps.pps = (const PPS*)h->ps.pps_ref->data;
    }

    if (h->ps.sps != (const SPS*)h->ps.sps_list[h->ps.pps->sps_id]->data) {
        av_buffer_unref(&h->ps.sps_ref);
        h->ps.sps = NULL;
        h->ps.sps_ref = av_buffer_ref(h->ps.sps_list[h->ps.pps->sps_id]);
        if (!h->ps.sps_ref)
            return AVERROR(ENOMEM);
        h->ps.sps = (const SPS*)h->ps.sps_ref->data;

        if (h->mb_width  != h->ps.sps->mb_width ||
            h->mb_height != h->ps.sps->mb_height ||
            h->cur_bit_depth_luma    != h->ps.sps->bit_depth_luma ||
            h->cur_chroma_format_idc != h->ps.sps->chroma_format_idc
        )
            needs_reinit = 1;

        if (h->bit_depth_luma    != h->ps.sps->bit_depth_luma ||
            h->chroma_format_idc != h->ps.sps->chroma_format_idc)
            needs_reinit         = 1;
    }
    sps = h->ps.sps;

    must_reinit = (h->context_initialized &&
                    (   16*sps->mb_width != h->avctx->coded_width
                     || 16*sps->mb_height != h->avctx->coded_height
                     || h->cur_bit_depth_luma    != sps->bit_depth_luma
                     || h->cur_chroma_format_idc != sps->chroma_format_idc
                     || h->mb_width  != sps->mb_width
                     || h->mb_height != sps->mb_height
                    ));
    if (h->avctx->pix_fmt == AV_PIX_FMT_NONE
        || (non_j_pixfmt(h->avctx->pix_fmt) != non_j_pixfmt(get_pixel_format(h, 0))))
        must_reinit = 1;

    if (first_slice && av_cmp_q(sps->sar, h->avctx->sample_aspect_ratio))
        must_reinit = 1;

    if (!h->setup_finished) {
        h->avctx->profile = ff_h364_get_profile(sps);
        h->avctx->level   = sps->level_idc;
        h->avctx->refs    = sps->ref_frame_count;

        h->mb_width  = sps->mb_width;
        h->mb_height = sps->mb_height;
        h->mb_num    = h->mb_width * h->mb_height;
        h->mb_stride = h->mb_width + 1;

        h->b_stride = h->mb_width * 4;

        h->chroma_y_shift = sps->chroma_format_idc <= 1; // 400 uses yuv420p

        h->width  = 16 * h->mb_width;
        h->height = 16 * h->mb_height;

        ret = init_dimensions(h);
        if (ret < 0)
            return ret;

        if (sps->video_signal_type_present_flag) {
            h->avctx->color_range = sps->full_range > 0 ? AVCOL_RANGE_JPEG
                                                        : AVCOL_RANGE_MPEG;
            if (sps->colour_description_present_flag) {
                if (h->avctx->colorspace != sps->colorspace)
                    needs_reinit = 1;
                h->avctx->color_primaries = sps->color_primaries;
                h->avctx->color_trc       = sps->color_trc;
                h->avctx->colorspace      = sps->colorspace;
            }
        }
    }

    if (!h->context_initialized || must_reinit || needs_reinit) {
        int flush_changes = h->context_initialized;
        h->context_initialized = 0;
        if (sl != h->slice_ctx) {
            av_log(h->avctx, AV_LOG_ERROR,
                   "changing width %d -> %d / height %d -> %d on "
                   "slice %d\n",
                   h->width, h->avctx->coded_width,
                   h->height, h->avctx->coded_height,
                   h->current_slice + 1);
            return AVERROR_INVALIDDATA;
        }

        av_assert1(first_slice);

        if (flush_changes)
            ff_h364_flush_change(h);

        if ((ret = get_pixel_format(h, 1)) < 0)
            return ret;
        h->avctx->pix_fmt = ret;

        av_log(h->avctx, AV_LOG_VERBOSE, "Reinit context to %dx%d, "
               "pix_fmt: %s\n", h->width, h->height, av_get_pix_fmt_name(h->avctx->pix_fmt));

        if ((ret = h364_slice_header_init(h)) < 0) {
            av_log(h->avctx, AV_LOG_ERROR,
                   "h364_slice_header_init() failed\n");
            return ret;
        }
    }

    return 0;
}

/* This function is called right after decoding the slice header for a first
 * slice in a field (or a frame). It decides whether we are decoding a new frame
 * or a second field in a pair and does the necessary setup.
 */
static int h364_field_start(H264Context *h, const H264SliceContext *sl, const H2645NAL *nal, int first_slice)
被調(diào)用
int ff_h364_queue_decode_slice(H264Context *h, const H2645NAL *nal)
被調(diào)用
static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI