Newest 'libx264' Questions - Stack Overflow

http://stackoverflow.com/questions/tagged/libx264

Articles published on the website

  • Creating a video from images using ffmpeg libav and libx264?

    8 March 2021, by marikaner

    I am trying to create a video from images using the ffmpeg library. The images have a size of 1920x1080 and are supposed to be encoded with H.264 using a .mkv container. I have come across various problems, thinking I am getting closer to a solution, but this one I am really stuck on. With the settings I use, the first X frames (around 40, depending on what and how many images I use for the video) of my video are not encoded. avcodec_encode_video2 does not return any error (return value is 0) with got_picture_ptr = 0. The result is a video that actually looks as expected, but the first seconds are weirdly jumpy.

    So this is how I create the video file:

    // m_codecContext is an instance variable of type AVCodecContext *
    // m_formatCtx is an instance variable of type AVFormatContext *
    
    // outputFileName is a valid filename ending with .mkv
    AVOutputFormat *oformat = av_guess_format(NULL, outputFileName, NULL);
    if (oformat == NULL)
    {
        oformat = av_guess_format("mpeg", NULL, NULL);
    }
    
    // oformat->video_codec is AV_CODEC_ID_H264
    AVCodec *codec = avcodec_find_encoder(oformat->video_codec);
    
    m_codecContext = avcodec_alloc_context3(codec);
    m_codecContext->codec_id = oformat->video_codec;
    m_codecContext->codec_type = AVMEDIA_TYPE_VIDEO;
    m_codecContext->gop_size = 30;
    m_codecContext->bit_rate = width * height * 4
    m_codecContext->width = width;
    m_codecContext->height = height;
    m_codecContext->time_base = (AVRational){1,frameRate};
    m_codecContext->max_b_frames = 1;
    m_codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
    
    m_formatCtx = avformat_alloc_context();
    m_formatCtx->oformat = oformat;
    m_formatCtx->video_codec_id = oformat->video_codec;
    
    snprintf(m_formatCtx->filename, sizeof(m_formatCtx->filename), "%s", outputFileName);
    
    AVStream *videoStream = avformat_new_stream(m_formatCtx, codec);
    if(!videoStream)
    {
       printf("Could not allocate stream\n");
    }
    videoStream->codec = m_codecContext;
    
    if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
    {
       m_codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }
    
    avcodec_open2(m_codecContext, codec, NULL) < 0);
    avio_open(&m_formatCtx->pb, outputFileName.toStdString().c_str(), AVIO_FLAG_WRITE);
    avformat_write_header(m_formatCtx, NULL);
    

    this is how the frames are added:

    void VideoCreator::writeImageToVideo(const QSharedPointer &img, int frameIndex)
    {
        AVFrame *frame = avcodec_alloc_frame();
    
        /* alloc image and output buffer */
    
        int size = m_codecContext->width * m_codecContext->height;
        int numBytes = avpicture_get_size(m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height);
    
        uint8_t *outbuf = (uint8_t *)malloc(numBytes);
        uint8_t *picture_buf = (uint8_t *)av_malloc(numBytes);
    
        int ret = av_image_fill_arrays(frame->data, frame->linesize, picture_buf, m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height, 1);
    
        frame->data[0] = picture_buf;
        frame->data[1] = frame->data[0] + size;
        frame->data[2] = frame->data[1] + size/4;
        frame->linesize[0] = m_codecContext->width;
        frame->linesize[1] = m_codecContext->width/2;
        frame->linesize[2] = m_codecContext->width/2;
    
        fflush(stdout);
    
    
        for (int y = 0; y < m_codecContext->height; y++)
        {
            for (int x = 0; x < m_codecContext->width; x++)
            {
                unsigned char b = img->bits()[(y * m_codecContext->width + x) * 4 + 0];
                unsigned char g = img->bits()[(y * m_codecContext->width + x) * 4 + 1];
                unsigned char r = img->bits()[(y * m_codecContext->width + x) * 4 + 2];
    
                unsigned char Y = (0.257 * r) + (0.504 * g) + (0.098 * b) + 16;
    
                frame->data[0][y * frame->linesize[0] + x] = Y;
    
                if (y % 2 == 0 && x % 2 == 0)
                {
                    unsigned char V = (0.439 * r) - (0.368 * g) - (0.071 * b) + 128;
                    unsigned char U = -(0.148 * r) - (0.291 * g) + (0.439 * b) + 128;
    
                    frame->data[1][y/2 * frame->linesize[1] + x/2] = U;
                    frame->data[2][y/2 * frame->linesize[2] + x/2] = V;
                }
            }
        }
    
        int pts = frameIndex;//(1.0 / 30.0) * 90.0 * frameIndex;
    
        frame->pts = pts;//av_rescale_q(m_codecContext->coded_frame->pts, m_codecContext->time_base, formatCtx->streams[0]->time_base); //(1.0 / 30.0) * 90.0 * frameIndex;
    
        int got_packet_ptr;
        AVPacket packet;
        av_init_packet(&packet);
        packet.data = outbuf;
        packet.size = numBytes;
        packet.stream_index = formatCtx->streams[0]->index;
        packet.flags |= AV_PKT_FLAG_KEY;
        packet.pts = packet.dts = pts;
        m_codecContext->coded_frame->pts = pts;
    
        ret = avcodec_encode_video2(m_codecContext, &packet, frame, &got_packet_ptr);
        if (got_packet_ptr != 0)
        {
            m_codecContext->coded_frame->pts = pts;  // Set the time stamp
    
            if (m_codecContext->coded_frame->pts != (0x8000000000000000LL))
            {
                pts = av_rescale_q(m_codecContext->coded_frame->pts, m_codecContext->time_base, formatCtx->streams[0]->time_base);
            }
            packet.pts = pts;
            if(m_codecContext->coded_frame->key_frame)
            {
               packet.flags |= AV_PKT_FLAG_KEY;
            }
    
            std::cout << "pts: " << packet.pts << ", dts: "  << packet.dts << std::endl;
    
            av_interleaved_write_frame(formatCtx, &packet);
            av_free_packet(&packet);
        }
    
        free(picture_buf);
        free(outbuf);
        av_free(frame);
        printf("\n");
    }
    

    and this is the cleanup:

    int numBytes = avpicture_get_size(m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height);
    int got_packet_ptr = 1;
    
    int ret;
    //        for(; got_packet_ptr != 0; i++)
    while (got_packet_ptr)
    {
        uint8_t *outbuf = (uint8_t *)malloc(numBytes);
    
        AVPacket packet;
        av_init_packet(&packet);
        packet.data = outbuf;
        packet.size = numBytes;
    
        ret = avcodec_encode_video2(m_codecContext, &packet, NULL, &got_packet_ptr);
        if (got_packet_ptr)
        {
            av_interleaved_write_frame(m_formatCtx, &packet);
        }
    
        av_free_packet(&packet);
        free(outbuf);
    }
    
    av_write_trailer(formatCtx);
    
    avcodec_close(m_codecContext);
    av_free(m_codecContext);
    printf("\n");
    

    I assume it might be tied to the PTS and DTS values, but I have tried EVERYTHING. The frame index seems to make the most sense. The images are correct, I can save them to files without any problems. I am running out of ideas. I would be incredibly thankful if there was someone out there who knew better than me...

    Cheers, marikaner

    UPDATE:

    If this is of any help this is the output at the end of the video encoding:

    [libx264 @ 0x7fffc00028a0] frame I:19    Avg QP:14.24  size:312420
    [libx264 @ 0x7fffc00028a0] frame P:280   Avg QP:19.16  size:148867
    [libx264 @ 0x7fffc00028a0] frame B:181   Avg QP:21.31  size: 40540
    [libx264 @ 0x7fffc00028a0] consecutive B-frames: 24.6% 75.4%
    [libx264 @ 0x7fffc00028a0] mb I  I16..4: 30.9% 45.5% 23.7%
    [libx264 @ 0x7fffc00028a0] mb P  I16..4:  4.7%  9.1%  4.5%  P16..4: 23.5% 16.6% 12.6%  0.0%  0.0%    skip:28.9%
    [libx264 @ 0x7fffc00028a0] mb B  I16..4:  0.6%  0.5%  0.3%  B16..8: 26.7% 11.0%  5.5%  direct: 3.9%  skip:51.5%  L0:39.4% L1:45.0% BI:15.6%
    [libx264 @ 0x7fffc00028a0] final ratefactor: 19.21
    [libx264 @ 0x7fffc00028a0] 8x8 transform intra:48.2% inter:47.3%
    [libx264 @ 0x7fffc00028a0] coded y,uvDC,uvAC intra: 54.9% 53.1% 30.4% inter: 25.4% 13.5% 4.2%
    [libx264 @ 0x7fffc00028a0] i16 v,h,dc,p: 41% 29% 11% 19%
    [libx264 @ 0x7fffc00028a0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 16% 26% 31%  3%  4%  3%  7%  3%  6%
    [libx264 @ 0x7fffc00028a0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 30% 26% 14%  4%  5%  4%  7%  4%  7%
    [libx264 @ 0x7fffc00028a0] i8c dc,h,v,p: 58% 26% 13%  3%
    [libx264 @ 0x7fffc00028a0] Weighted P-Frames: Y:17.1% UV:3.6%
    [libx264 @ 0x7fffc00028a0] ref P L0: 63.1% 21.4% 11.4%  4.1%  0.1%    
    [libx264 @ 0x7fffc00028a0] ref B L0: 85.7% 14.3%
    [libx264 @ 0x7fffc00028a0] kb/s:27478.30
    
  • Convert .mp4 to .ts using H264 at constant framerate 25fps [closed]

    4 March 2021, by losing-my-marbles

    I've been trying to do this conversion for a couple of days reading through forums

    ffmpeg -i in1.mp4 -vcodec libx264 -s 720x576 -vf "fps=25"-vsync cfr -b:v 2300k -acodec aac -b:a 128k out1.ts

    I've tried the below flags found in other forums.

    ... -r 25 -vf fps=25 -filter:v fps=25 -filter:v fps=fps=25

    I then read the file using mediainfo and keep getting the same result;

    Frame rate mode : VFR Frame rate mode : Variable Frame rate : 46.875 Frame rate : 46.875 FPS (1024 SPF)

  • iOS Build PJSIP with FFmpeg+libx264

    22 February 2021, by Meonardo

    I have built the FFmpeg with libx264 into static libs, here is my directory tree.

    ./ffmpeg
    ├── include
    │   ├── libavcodec
    │   │   ├── ac3_parser.h
    │   │   ├── adts_parser.h
    │   │   ├── avcodec.h
    │   │   ├── avdct.h
    │   │   ├── avfft.h
    │   │   ├── bsf.h
    │   │   ├── codec.h
    │   │   ├── codec_desc.h
    │   │   ├── codec_id.h
    │   │   ├── codec_par.h
    │   │   ├── d3d11va.h
    │   │   ├── dirac.h
    │   │   ├── dv_profile.h
    │   │   ├── dxva2.h
    │   │   ├── jni.h
    │   │   ├── mediacodec.h
    │   │   ├── packet.h
    │   │   ├── qsv.h
    │   │   ├── vaapi.h
    │   │   ├── vdpau.h
    │   │   ├── version.h
    │   │   ├── videotoolbox.h
    │   │   ├── vorbis_parser.h
    │   │   └── xvmc.h
    │   ├── libavdevice
    │   │   ├── avdevice.h
    │   │   └── version.h
    │   ├── libavfilter
    │   │   ├── avfilter.h
    │   │   ├── buffersink.h
    │   │   ├── buffersrc.h
    │   │   └── version.h
    │   ├── libavformat
    │   │   ├── avformat.h
    │   │   ├── avio.h
    │   │   └── version.h
    │   ├── libavutil
    │   │   ├── adler32.h
    │   │   ├── aes.h
    │   │   ├── aes_ctr.h
    │   │   ├── attributes.h
    │   │   ├── audio_fifo.h
    │   │   ├── avassert.h
    │   │   ├── avconfig.h
    │   │   ├── avstring.h
    │   │   ├── avutil.h
    │   │   ├── base64.h
    │   │   ├── blowfish.h
    │   │   ├── bprint.h
    │   │   ├── bswap.h
    │   │   ├── buffer.h
    │   │   ├── camellia.h
    │   │   ├── cast5.h
    │   │   ├── channel_layout.h
    │   │   ├── common.h
    │   │   ├── cpu.h
    │   │   ├── crc.h
    │   │   ├── des.h
    │   │   ├── dict.h
    │   │   ├── display.h
    │   │   ├── dovi_meta.h
    │   │   ├── downmix_info.h
    │   │   ├── encryption_info.h
    │   │   ├── error.h
    │   │   ├── eval.h
    │   │   ├── ffversion.h
    │   │   ├── fifo.h
    │   │   ├── file.h
    │   │   ├── frame.h
    │   │   ├── hash.h
    │   │   ├── hdr_dynamic_metadata.h
    │   │   ├── hmac.h
    │   │   ├── hwcontext.h
    │   │   ├── hwcontext_cuda.h
    │   │   ├── hwcontext_d3d11va.h
    │   │   ├── hwcontext_drm.h
    │   │   ├── hwcontext_dxva2.h
    │   │   ├── hwcontext_mediacodec.h
    │   │   ├── hwcontext_opencl.h
    │   │   ├── hwcontext_qsv.h
    │   │   ├── hwcontext_vaapi.h
    │   │   ├── hwcontext_vdpau.h
    │   │   ├── hwcontext_videotoolbox.h
    │   │   ├── hwcontext_vulkan.h
    │   │   ├── imgutils.h
    │   │   ├── intfloat.h
    │   │   ├── intreadwrite.h
    │   │   ├── lfg.h
    │   │   ├── log.h
    │   │   ├── lzo.h
    │   │   ├── macros.h
    │   │   ├── mastering_display_metadata.h
    │   │   ├── mathematics.h
    │   │   ├── md5.h
    │   │   ├── mem.h
    │   │   ├── motion_vector.h
    │   │   ├── murmur3.h
    │   │   ├── opt.h
    │   │   ├── parseutils.h
    │   │   ├── pixdesc.h
    │   │   ├── pixelutils.h
    │   │   ├── pixfmt.h
    │   │   ├── random_seed.h
    │   │   ├── rational.h
    │   │   ├── rc4.h
    │   │   ├── replaygain.h
    │   │   ├── ripemd.h
    │   │   ├── samplefmt.h
    │   │   ├── sha.h
    │   │   ├── sha512.h
    │   │   ├── spherical.h
    │   │   ├── stereo3d.h
    │   │   ├── tea.h
    │   │   ├── threadmessage.h
    │   │   ├── time.h
    │   │   ├── timecode.h
    │   │   ├── timestamp.h
    │   │   ├── tree.h
    │   │   ├── twofish.h
    │   │   ├── tx.h
    │   │   ├── version.h
    │   │   ├── video_enc_params.h
    │   │   └── xtea.h
    │   ├── libpostproc
    │   │   ├── postprocess.h
    │   │   └── version.h
    │   ├── libswresample
    │   │   ├── swresample.h
    │   │   └── version.h
    │   ├── libswscale
    │   │   ├── swscale.h
    │   │   └── version.h
    │   └── libx264
    │       ├── x264.h
    │       └── x264_config.h
    └── lib
        ├── libavcodec.a
        ├── libavdevice.a
        ├── libavfilter.a
        ├── libavformat.a
        ├── libavutil.a
        ├── libpostproc.a
        ├── libswresample.a
        ├── libswscale.a
        └── libx264.a
    

    The final lib was created successfully, no error message in log file, but when I import the lib to my Xcode Project, the linker give me tons of errors(missing symbols like: Undefined symbol: _pjsua_vid_codec_set_priority). I found the pjsua_vid.o is very small(200Bytes) compare to my pjsip+openh264 build file(was 47KB), perhaps this is the reason cause the link error.

    Here is my build log: log_file

    the build script I am using:

    #!/bin/sh
    
    # see http://stackoverflow.com/a/3915420/318790
    function realpath { echo $(cd $(dirname "$1"); pwd)/$(basename "$1"); }
    __FILE__=`realpath "$0"`
    __DIR__=`dirname "${__FILE__}"`
    
    # download
    function download() {
        "${__DIR__}/download.sh" "$1" "$2" #--no-cache
    }
    
    BASE_DIR="$1"
    PJSIP_URL="https://github.com/pjsip/pjproject/archive/2.10.zip"
    #http://www.pjsip.org/release/2.8.0/pjproject-2.8.0.tar.bz2
    PJSIP_DIR="$1/src"
    LIB_PATHS=("pjlib/lib" \
               "pjlib-util/lib" \
               "pjmedia/lib" \
               "pjnath/lib" \
               "pjsip/lib" \
               "third_party/lib")
    
    OPENSSL_PREFIX=
    FFMPEG_PREFIX=
    OPENH264_PREFIX=
    OPUS_PREFIX=
    while [ "$#" -gt 0 ]; do
        case $1 in
            --with-openssl)
                if [ "$#" -gt 1 ]; then
                    OPENSSL_PREFIX=$(python -c "import os,sys; print os.path.realpath(sys.argv[1])" "$2")
                    shift 2
                    continue
                else
                    echo 'ERROR: Must specify a non-empty "--with-openssl PREFIX" argument.' >&2
                    exit 1
                fi
                ;;
            --with-openh264)
                if [ "$#" -gt 1 ]; then
                    OPENH264_PREFIX=$(python -c "import os,sys; print os.path.realpath(sys.argv[1])" "$2")
                    shift 2
                    continue
                else
                    echo 'ERROR: Must specify a non-empty "--with-openh264 PREFIX" argument.' >&2
                    exit 1
                fi
                ;;
            --with-ffmpeg)
                if [ "$#" -gt 1 ]; then
                    FFMPEG_PREFIX=$(python -c "import os,sys; print os.path.realpath(sys.argv[1])" "$2")
                    shift 2
                    continue
                else
                    echo 'ERROR: Must specify a non-empty "--with-ffmpeg PREFIX" argument.' >&2
                    exit 1
                fi
                ;;
            --with-opus)
                if [ "$#" -gt 1 ]; then
                    OPUS_PREFIX=$(python -c "import os,sys; print os.path.realpath(sys.argv[1])" "$2")
                    shift 2
                    continue
                else
                    echo 'ERROR: Must specify a non-empty "--with-opus PREFIX" argument.' >&2
                    exit 1
                fi
                ;;
        esac
    
        shift
    done
    
    function config_site() {
        SOURCE_DIR=$1
        PJSIP_CONFIG_PATH="${SOURCE_DIR}/pjlib/include/pj/config_site.h"
        HAS_VIDEO=
    
        echo "Creating config_site.h ..."
    
        if [ -f "${PJSIP_CONFIG_PATH}" ]; then
            rm "${PJSIP_CONFIG_PATH}"
        fi
    
        echo "#define PJ_CONFIG_IPHONE 1" >> "${PJSIP_CONFIG_PATH}"
        echo "#define PJ_HAS_IPV6 1" >> "${PJSIP_CONFIG_PATH}" # Enable IPV6
        if [[ ${OPENH264_PREFIX} ]]; then
            # echo "#define PJMEDIA_HAS_VID_TOOLBOX_CODEC 1" >> "${PJSIP_CONFIG_PATH}"
            # echo "#define PJMEDIA_HAS_OPENH264_CODEC 1" >> "${PJSIP_CONFIG_PATH}"
            echo "#define PJMEDIA_HAS_FFMPEG_VID_CODEC 1" >> "${PJSIP_CONFIG_PATH}"
            HAS_VIDEO=1
        fi
        if [[ ${HAS_VIDEO} ]]; then
            echo "#define PJMEDIA_HAS_VIDEO 1" >> "${PJSIP_CONFIG_PATH}"
            echo "#define PJMEDIA_VIDEO_DEV_HAS_OPENGL 1" >> "${PJSIP_CONFIG_PATH}"
            echo "#define PJMEDIA_VIDEO_DEV_HAS_OPENGL_ES 1" >> "${PJSIP_CONFIG_PATH}"
            echo "#define PJMEDIA_VIDEO_DEV_HAS_IOS_OPENGL 1" >> "${PJSIP_CONFIG_PATH}"
            echo "#include ES3/glext.h>" >> "${PJSIP_CONFIG_PATH}"
        fi
        echo "#include config_site_sample.h>" >> "${PJSIP_CONFIG_PATH}"
    }
    
    function clean_libs () {
        ARCH=${1}
        for SRC_DIR in ${LIB_PATHS[*]}; do
            DIR="${PJSIP_DIR}/${SRC_DIR}"
            if [ -d "${DIR}" ]; then
                rm -rf "${DIR}"/*
            fi
    
            DIR="${PJSIP_DIR}/${SRC_DIR}-${ARCH}"
            if [ -d "${DIR}" ]; then
                rm -rf "${DIR}"
            fi
        done
    }
    
    function copy_libs () {
        ARCH=${1}
    
        for SRC_DIR in ${LIB_PATHS[*]}; do
            SRC_DIR="${PJSIP_DIR}/${SRC_DIR}"
            DST_DIR="${SRC_DIR}-${ARCH}"
            if [ -d "${DST_DIR}" ]; then
                rm -rf "${DST_DIR}"
            fi
            cp -R "${SRC_DIR}" "${DST_DIR}"
            rm -rf "${SRC_DIR}"/* # delete files because this directory will be used for the final lipo output
        done
    }
    
    function _build() {
        pushd . > /dev/null
        cd ${PJSIP_DIR}
    
        ARCH=$1
        LOG=${BASE_DIR}/${ARCH}.log
    
        # configure
        CONFIGURE="./configure-iphone"
        if [[ ${OPENSSL_PREFIX} ]]; then
            CONFIGURE="${CONFIGURE} --with-ssl=${OPENSSL_PREFIX}"
        fi
        # if [[ ${OPENH264_PREFIX} ]]; then
        #     CONFIGURE="${CONFIGURE} --with-openh264=${OPENH264_PREFIX}"
        # fi
        if [[ ${FFMPEG_PREFIX} ]]; then
            CONFIGURE="${CONFIGURE} --with-ffmpeg=${FFMPEG_PREFIX}"
        fi
        if [[ ${OPUS_PREFIX} ]]; then
            CONFIGURE="${CONFIGURE} --with-opus=${OPUS_PREFIX}"
        fi
    
        # flags
        if [[ ! ${CFLAGS} ]]; then
            export CFLAGS=
        fi
        if [[ ! ${LDFLAGS} ]]; then
            export LDFLAGS=
        fi
        if [[ ${OPENSSL_PREFIX} ]]; then
            export CFLAGS="${CFLAGS} -I${OPENSSL_PREFIX}/include"
            export LDFLAGS="${LDFLAGS} -L${OPENSSL_PREFIX}/lib"
        fi
        # if [[ ${OPENH264_PREFIX} ]]; then
        #     export CFLAGS="${CFLAGS} -I${OPENH264_PREFIX}/include"
        #     export LDFLAGS="${LDFLAGS} -L${OPENH264_PREFIX}/lib"
        # fi
        if [[ ${FFMPEG_PREFIX} ]]; then
            export CFLAGS="${CFLAGS} -I${FFMPEG_PREFIX}/include"
            export LDFLAGS="${LDFLAGS} -L${FFMPEG_PREFIX}/lib"
        fi
        export LDFLAGS="${LDFLAGS} -lstdc++"
    
        echo "Building for ${ARCH}..."
    
        clean_libs ${ARCH}
    
        make distclean > ${LOG} 2>&1
        ARCH="-arch ${ARCH}" ${CONFIGURE} >> ${LOG} 2>&1
        make dep >> ${LOG} 2>&1
        make clean >> ${LOG}
        make lib >> ${LOG} 2>&1
    
        copy_libs ${ARCH}
    }
    
    # function armv7() {
    #     export DEVPATH="`xcrun -sdk iphoneos --show-sdk-platform-path`/Developer"
    #     export CFLAGS="-miphoneos-version-min=8.0"
    #     export LDFLAGS=
    #     _build "armv7"
    # }
    # function armv7s() {
    #     export DEVPATH="`xcrun -sdk iphoneos --show-sdk-platform-path`/Developer"
    #     export CFLAGS="-miphoneos-version-min=8.0"
    #     export LDFLAGS=
    #     _build "armv7s"
    # }
    function arm64() {
        export DEVPATH="`xcrun -sdk iphoneos --show-sdk-platform-path`/Developer"
        export CFLAGS="-miphoneos-version-min=8.0"
        export LDFLAGS=
        _build "arm64"
    }
    function i386() {
        export DEVPATH="`xcrun -sdk iphonesimulator --show-sdk-platform-path`/Developer"
        export CFLAGS="-O2 -m32 -mios-simulator-version-min=8.0"
        export LDFLAGS="-O2 -m32 -mios-simulator-version-min=8.0"
        _build "i386"
    }
    function x86_64() {
        export DEVPATH="`xcrun -sdk iphonesimulator --show-sdk-platform-path`/Developer"
        export CFLAGS="-O2 -m32 -mios-simulator-version-min=8.0"
        export LDFLAGS="-O2 -m32 -mios-simulator-version-min=8.0"
        _build "x86_64"
    }
    
    function lipo() {
        TMP=`mktemp -t lipo`
        echo "Lipo libs... (${TMP})"
    
        for LIB_DIR in ${LIB_PATHS[*]}; do # loop over libs
            DST_DIR="${PJSIP_DIR}/${LIB_DIR}"
    
            # use the first architecture to find all libraries
            PATTERN_DIR="${DST_DIR}-$1"
            for PATTERN_FILE in `ls -l1 "${PATTERN_DIR}"`; do
                OPTIONS=""
    
                # loop over all architectures and collect the current library
                for ARCH in "$@"; do
                    FILE="${DST_DIR}-${ARCH}/${PATTERN_FILE/-$1-/-${ARCH}-}"
                    if [ -e "${FILE}" ]; then
                        OPTIONS="$OPTIONS -arch ${ARCH} ${FILE}"
                    fi
                done
    
                if [ "$OPTIONS" != "" ]; then
                    OUTPUT_PREFIX=$(dirname "${DST_DIR}")
                    OUTPUT="${OUTPUT_PREFIX}/lib/${PATTERN_FILE/-$1-/-}"
    
                    OPTIONS="${OPTIONS} -create -output ${OUTPUT}"
                    echo "$OPTIONS" >> "${TMP}"
                fi
            done
        done
    
        while read LINE; do
            xcrun -sdk iphoneos lipo ${LINE}
        done < "${TMP}"
    }
    
    # download "${PJSIP_URL}" "${PJSIP_DIR}"
    config_site "${PJSIP_DIR}"
    arm64 && i386 && x86_64
    lipo arm64 i386 x86_64
    

    Thanks for any advice.

  • Generating all P frame intra refresh H264 with x264

    3 February 2021, by Andrew

    I am trying to generate a periodic intra refresh h264 stream with only P frames using ffmpeg and x264 but I always get an I frame at the start.

    Is there a way with x264 to create a P frame only stream?

    Commands I am using:

    ffmpeg -f lavfi -re -i testsrc=duration=5:size=1920x1080:rate=30000/1001 -s 1920x1080 -pix_fmt yuv420p -f rawvideo out.yuv
    x264 --input-res 1920x1080 --intra-refresh out.yuv --b-pyramid none -b 0 --ref 0  -o out.264
    

    Verification:

        ffprobe -show_frames out.264 |grep pict_type=I
    

    Or just looking at the x264 output e.g.

    yuv [info]: 1920x1080p 0:0 @ 25/1 fps (cfr)
    x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
    x264 [info]: profile High, level 4.0, 4:2:0, 8-bit
    x264 [info]: frame I:1     Avg QP:13.63  size: 12189
    x264 [info]: frame P:149   Avg QP:13.59  size:   874
    x264 [info]: mb I  I16..4: 78.7% 18.6%  2.7%
    x264 [info]: mb P  I16..4:  2.3%  0.1%  0.0%  P16..4:  3.2%  0.3%  0.0%  0.0%  0.0%    skip:94.1%
    x264 [info]: 8x8 transform intra:7.6% inter:91.5%
    x264 [info]: coded y,uvDC,uvAC intra: 1.3% 18.9% 3.6% inter: 0.1% 1.1% 0.1%
    x264 [info]: i16 v,h,dc,p: 86%  6%  1%  7%
    x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 42% 22% 36%  0%  0%  0%  0%  0%  0%
    x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 29% 30% 32%  3%  1%  3%  0%  3%  0%
    x264 [info]: i8c dc,h,v,p: 28%  7% 55%  9%
    x264 [info]: Weighted P-Frames: Y:0.0% UV:0.0%
    x264 [info]: kb/s:189.96
    
    encoded 150 frames, 66.76 fps, 189.96 kb/s
    
  • Proper use of `nalu_process` callback in x264

    26 January 2021, by gspr

    I wish to make use of libx264's low-latency encoding mechanism, whereby a user-provided callback is called as soon as a single NAL unit is available instead of having to wait for a whole frame to be encoded before starting processing.

    The x264 documentation states the following about that facility:

    /* Optional low-level callback for low-latency encoding.  Called for each output NAL unit
     * immediately after the NAL unit is finished encoding.  This allows the calling application
     * to begin processing video data (e.g. by sending packets over a network) before the frame
     * is done encoding.
     *
     * This callback MUST do the following in order to work correctly:
     * 1) Have available an output buffer of at least size nal->i_payload*3/2 + 5 + 64.
     * 2) Call x264_nal_encode( h, dst, nal ), where dst is the output buffer.
     * After these steps, the content of nal is valid and can be used in the same way as if
     * the NAL unit were output by x264_encoder_encode.
     *
     * This does not need to be synchronous with the encoding process: the data pointed to
     * by nal (both before and after x264_nal_encode) will remain valid until the next
     * x264_encoder_encode call.  The callback must be re-entrant.
     *
     * This callback does not work with frame-based threads; threads must be disabled
     * or sliced-threads enabled.  This callback also does not work as one would expect
     * with HRD -- since the buffering period SEI cannot be calculated until the frame
     * is finished encoding, it will not be sent via this callback.
     *
     * Note also that the NALs are not necessarily returned in order when sliced threads is
     * enabled.  Accordingly, the variable i_first_mb and i_last_mb are available in
     * x264_nal_t to help the calling application reorder the slices if necessary.
     *
     * When this callback is enabled, x264_encoder_encode does not return valid NALs;
     * the calling application is expected to acquire all output NALs through the callback.
     *
     * It is generally sensible to combine this callback with a use of slice-max-mbs or
     * slice-max-size.
     *
     * The opaque pointer is the opaque pointer from the input frame associated with this
     * NAL unit. This helps distinguish between nalu_process calls from different sources,
     * e.g. if doing multiple encodes in one process.
     */
    void (*nalu_process)( x264_t *h, x264_nal_t *nal, void *opaque );
    

    This seems straight forward enough. However, when I run the following dummy code, I get a segfault on the marked line. I've tried to add some debugging to x264_nal_encode itself to understand where it goes wrong, but it seems to be the function call itself that results in a segfault. Am I missing something here? (Let's ignore the fact that the use of assert probably makes cb non-reentrant – it's only there to indicate to the reader that my workspace buffer is more than large enough.)

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define WS_SIZE 10000000
    uint8_t * workspace;
    
    void cb(x264_t * h, x264_nal_t * nal, void * opaque)
    {
      assert((nal->i_payload*3)/2 + 5 + 64 < WS_SIZE);
      x264_nal_encode(h, workspace, nal); // Segfault here.
      // Removed: Process nal.
    }
    
    int main(int argc, char ** argv)
    {
      uint8_t * fake_frame = malloc(1280*720*3);
      memset(fake_frame, 0, 1280*720*3);
    
      workspace = malloc(WS_SIZE);
    
      x264_param_t param;
      int status = x264_param_default_preset(&param, "ultrafast", "zerolatency");
      assert(status == 0);
    
      param.i_csp = X264_CSP_RGB;
      param.i_width = 1280;
      param.i_height = 720;
      param.i_threads = 1;
      param.i_lookahead_threads = 1;
      param.i_frame_total = 0;
      param.i_fps_num = 30;
      param.i_fps_den = 1;
      param.i_slice_max_size = 1024;
      param.b_annexb = 1;
      param.nalu_process = cb;
    
      status = x264_param_apply_profile(&param, "high444");
      assert(status == 0);
    
      x264_t * h = x264_encoder_open(&param);
      assert(h);
    
      x264_picture_t pic;
      status = x264_picture_alloc(&pic, param.i_csp, param.i_width, param.i_height);
      assert(pic.img.i_plane == 1);
    
      x264_picture_t pic_out;
      x264_nal_t * nal; // Not used. We process NALs in cb.
      int i_nal;
    
      for (int i = 0; i < 100; ++i)
      {
        pic.i_pts = i;
        pic.img.plane[0] = fake_frame;
        status = x264_encoder_encode(h, &nal, &i_nal, &pic, &pic_out);
      }
    
      x264_encoder_close(h);
      x264_picture_clean(&pic);
      free(workspace);
      free(fake_frame);
      return 0;
    }
    

    Edit: The segfault happens the first time cb calls x264_nal_encode. If I switch to a different preset, where more frames are encoded before the first callback happens, then several successful calls to x264_encoder_encode are made before the first callback, and hence segfault, occurs.