openh264dec中finish_frame的逻辑和avviddec比起来比较简单,在handle_frame中,buffer先送给解码器解码(DecodeFrameNoDelay
),然后调用gst_video_decoder_finish_frame
将解码后的buffer发到downstream。
DecodeFrameNoDelay解码,返回yuvdata,完成后unmap input_buffer:
openh264dec->decoder->DecodeFrameNoDelay (map_info.data, map_info.size,
yuvdata, &dst_buf_info);
gst_buffer_unmap (frame->input_buffer, &map_info);
gst_video_frame_map()将在GstVideoFrame结构中填入buffer的像素以及所需的各种视频信息。
gboolean
gst_video_frame_map (GstVideoFrame * frame, GstVideoInfo * info, GstBuffer * buffer, GstMapFlags flags)
使用@info和@buffer来填入到@frame,地址会被传给分配在堆栈中的#GstVideoFrame结构。
可以使用访问器宏访问,如:
GST_VIDEO_FRAME_COMP_DATA()
GST_VIDEO_FRAME_PLANE_DATA()
GST_VIDEO_FRAME_COMP_STRIDE()
GST_VIDEO_FRAME_PLANE_STRIDE()
这个功能的目的是使你能够很容易地获得视频像素,而不需要担心太多细节问题。
比如视频数据是被分配在一个连续的内存块中还是多个内存块(例如,对于每一个plane都有一个内存块),或者是否使用自定义strides和自定义plane偏移(由每个缓冲区上的GstVideoMeta记录)。
这个函数只是用正确的值填充#GstVideoFrame结构
,使用访问器宏,可以很容易地访问数据。它还会为你映射底层的内存块。
gst_video_frame_map的使用从ffmpeg avviddec和openh264dec的实现也可以看到,能方便的把解码器解码的数据放到plane内存块中。
/**
* GstVideoFrame:
* @info: the #GstVideoInfo
* @flags: #GstVideoFrameFlags for the frame
* @buffer: the mapped GstBuffer's buffer
* @meta: pointer to metadata if any
* @id: id of the mapped frame. the id can for example be used to
* identify the frame in case of multiview video.
* @data: pointers to the plane data
* @map: mappings of the planes
*
* A video frame obtained from gst_video_frame_map()
*/
struct _GstVideoFrame {
GstVideoInfo info;
GstVideoFrameFlags flags;
GstBuffer *buffer;
gpointer meta;
gint id;
gpointer data[GST_VIDEO_MAX_PLANES];
GstMapInfo map[GST_VIDEO_MAX_PLANES];
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
辅助函数,为@decoder当前的#GstVideoCodecState分配一个缓冲区来容纳一个视频帧。子类应该已经配置了视频状态并设置了src pad caps。从openH264dec和avdec_h264中都可以看到,最后解码的数据要先allocate_output_frame,然后copy数据到这个里面,avviddec里面的处理需要看get_output_buffer函数的实现。
在openh264dec中,通过gst_video_decoder_finish_frame
将解码后的数据push到downstream,如果没有提供输出数据,frame被视为skipped。在任何情况下,frame都被视为finished和released。
因为output state部分配置的是I420,所以在进行数据copy的时候,是yuv依次copy:
// i = 0; Y plane
// i = 1; U plane
// i = 2; V plane
for (i = 0; i < 3; i++) {
p = GST_VIDEO_FRAME_COMP_DATA (&video_frame, i);
row_stride = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, i);
component_width = GST_VIDEO_FRAME_COMP_WIDTH (&video_frame, i);
component_height = GST_VIDEO_FRAME_COMP_HEIGHT (&video_frame, i);
src_width =
i <
1 ? dst_buf_info.UsrData.sSystemBuffer.
iStride[0] : dst_buf_info.UsrData.sSystemBuffer.iStride[1];
for (row = 0; row < component_height; row++) {
memcpy (p, yuvdata[i], component_width);
p += row_stride;
yuvdata[i] += src_width;
}
}