QtMultimedia. Qt 5.1. QVideoFrame converting in another struct



  • Hi, all.

    I need to create h264 stream from camera. Unfortunately, QVideoProbe::setSource( some_QMediaRecorder ) always return false (both in Windows and Linux) and I can't get already encoded frames.
    I inherit QAbstractVideoSurface, make QCamera::setViewFinder for my class and now I give all QVideoFrame's from camera in YUV420P format. I need to encode its and will use x264. For encoding I should convert QVideoFrame into x264_image_t.

    @typedef struct
    {
    int i_csp; /* Colorspace /
    int i_plane; /
    Number of image planes /
    int i_stride[4]; /
    Strides for each plane */
    uint8_t plane[4]; / Pointers to each plane */
    } x264_image_t;@

    Does the QVideoFrame::bits() method return pointer to plain buffer, contains all plains of picture? How I can convert it? x264 expects YUV420P and I need just copy frame.



  • Hi
    I have the same problem.
    Do you find any solution?



  • [quote author="jmimi" date="1387821006"]Hi
    I have the same problem.
    Do you find any solution?[/quote]

    Yes. I use avpicture_fill(...) for copy QVideoFrame into AVPicture and sws_scale(...) for converting this picture into x_264_picture_t with YUV420P colorspace.

    @void H264Encoder::encodeFrame(const QVideoFrame& frame)
    {
    if (!frame.isReadable() || !frame.isMapped())
    return;
    //m_in_pixel_format = avcodec::AV_PIX_FMT_RGB32;
    if (m_in_pixel_format == PIX_FMT_NONE)
    {
    if ( !this->set_pix_fmt(frame) )
    return;
    }

    size_t in_width = frame.width();
    size_t in_height = frame.height();

    if (!m_sws_ctx)
    {
    m_sws_ctx = sws_getContext(in_width, in_height, m_in_pixel_format,
    m_out_width, m_out_height, m_out_pixel_format, SWS_FAST_BILINEAR, NULL, NULL, NULL);
    if (!m_sws_ctx)
    {
    qDebug() << "libswscale: Error creating sws context!";
    return;
    }
    }

    //copy frame from QVideoFrame into m_pic_raw
    int bytes_copied = avpicture_fill(&m_pic_raw, const_cast<uint8_t*>(frame.bits()),
    m_in_pixel_format, in_width, in_height);

    if (bytes_copied < 0)
    {
    qDebug() << "H264Encoder: error calling avpicture_fill(...)!";
    return;
    }

    //convert img into m_out_format and save in m_in_pic
    int scaled_img_height = sws_scale(m_sws_ctx, m_pic_raw.data, m_pic_raw.linesize, 0, in_height,
    m_in_pic->img.plane, m_in_pic->img.i_stride);

    if ( scaled_img_height < 0 || (size_t)scaled_img_height != m_out_height )
    {
    qDebug() << "Scaling failed!";
    return;
    }

    m_in_pic->i_pts = m_pts++;

    int res = x264_encoder_encode(m_encoder, &m_nals, &m_num_nals, m_in_pic, m_out_pic);
    if (res < 0)
    {
    qDebug() << "x264_encode error!";
    return;
    }

    m_last_frame_sz = res;

        //create frame_t for every NAL unit
    

    std::vector<Frame_t> result;
    this->get_encoded_frame(result);
    for (auto i = result.cbegin(); i != result.cend(); i++)
    {
    SharedEncodedFrame shared_result;
    shared_result << *i;
    emit newEncodedFrame(shared_result);
    }
    }

    bool H264Encoder::get_encoded_frame( std::vector<Frame_t>& buf )const
    {
    if (!m_last_frame_sz)
    return false;

    buf.clear();
    buf.resize(m_num_nals);

    for (int i = 0; i < m_num_nals; i++)
    {
    std::copy((const char*)m_nals[i].p_payload + 4, (const char*)m_nals[i].p_payload +
    m_nals[i].i_payload, std::back_inserter(buf[i]));
    }

    return true;
    }
    @

    where I have next members:
    @x264_param_t* m_params;

    x264_t* m_encoder;

    x264_picture_t *m_in_pic, *m_out_pic;

    PixelFormat m_in_pixel_format;
    PixelFormat m_out_pixel_format;

    size_t m_out_height;
    size_t m_out_width;

    size_t m_fps;

    //input frame;
    AVPicture m_pic_raw;

    x264_nal_t* m_nals;
    int m_num_nals;
    size_t m_last_frame_sz;

    int m_pts;
    SwsContext* m_sws_ctx;@



  • Oh, thanks for code.
    How you trap frames to ?
    @void H264Encoder::encodeFrame(const QVideoFrame& frame)
    ..@



  • I create subclass of QAbstractVideoSurface and set it as a viewfinder in QCamera.
    MySurface have method present(QVideoFrame) which call H264Encoder::encodeFrame(...).



  • Thanks dimanx.
    QAbstractVideoSurface is the point.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.