/* parses the first CMML packet (the ident header) */ static void gst_cmml_dec_parse_ident_header (GstCmmlDec * dec, GstBuffer * buffer) { guint8 *data = GST_BUFFER_DATA (buffer); /* the ident header has a fixed length */ if (GST_BUFFER_SIZE (buffer) != CMML_IDENT_HEADER_SIZE) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("wrong ident header size: %d", GST_BUFFER_SIZE (buffer))); dec->flow_return = GST_FLOW_ERROR; return; } data += 8; dec->major = GST_READ_UINT16_LE (data); data += 2; dec->minor = GST_READ_UINT16_LE (data); data += 2; dec->granulerate_n = GST_READ_UINT64_LE (data); data += 8; dec->granulerate_d = GST_READ_UINT64_LE (data); data += 8; dec->granuleshift = GST_READ_UINT8 (data); GST_INFO_OBJECT (dec, "bitstream initialized " "(major: %" G_GINT16_FORMAT " minor: %" G_GINT16_FORMAT " granulerate_n: %" G_GINT64_FORMAT " granulerate_d: %" G_GINT64_FORMAT " granuleshift: %d)", dec->major, dec->minor, dec->granulerate_n, dec->granulerate_d, dec->granuleshift); dec->flow_return = GST_FLOW_OK; }
static GstFlowReturn gst_nuv_demux_extended_header_load (GstNuvDemux * nuv, nuv_extended_header ** h_ret) { unsigned char *data; GstBuffer *buff = NULL; nuv_extended_header *h; GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 512, TRUE, &buff); if (res != GST_FLOW_OK) { if (buff != NULL) { gst_buffer_unref (buff); } return res; } h = g_new0 (nuv_extended_header, 1); data = buff->data; h->i_version = GST_READ_UINT32_LE (&data[0]); h->i_video_fcc = GST_MAKE_FOURCC (data[4], data[5], data[6], data[7]); h->i_audio_fcc = GST_MAKE_FOURCC (data[8], data[9], data[10], data[11]); h->i_audio_sample_rate = GST_READ_UINT32_LE (&data[12]); h->i_audio_bits_per_sample = GST_READ_UINT32_LE (&data[16]); h->i_audio_channels = GST_READ_UINT32_LE (&data[20]); h->i_audio_compression_ratio = GST_READ_UINT32_LE (&data[24]); h->i_audio_quality = GST_READ_UINT32_LE (&data[28]); h->i_rtjpeg_quality = GST_READ_UINT32_LE (&data[32]); h->i_rtjpeg_luma_filter = GST_READ_UINT32_LE (&data[36]); h->i_rtjpeg_chroma_filter = GST_READ_UINT32_LE (&data[40]); h->i_lavc_bitrate = GST_READ_UINT32_LE (&data[44]); h->i_lavc_qmin = GST_READ_UINT32_LE (&data[48]); h->i_lavc_qmin = GST_READ_UINT32_LE (&data[52]); h->i_lavc_maxqdiff = GST_READ_UINT32_LE (&data[56]); h->i_seekable_offset = GST_READ_UINT64_LE (&data[60]); h->i_keyframe_adjust_offset = GST_READ_UINT64_LE (&data[68]); GST_DEBUG_OBJECT (nuv, "ex hdr: v=%d vffc=%4.4s afcc=%4.4s %dHz %dbits ach=%d acr=%d aq=%d" "rtjpeg q=%d lf=%d lc=%d lavc br=%d qmin=%d qmax=%d maxqdiff=%d seekableoff=%lld keyfao=%lld", h->i_version, (gchar *) & h->i_video_fcc, (gchar *) & h->i_audio_fcc, h->i_audio_sample_rate, h->i_audio_bits_per_sample, h->i_audio_channels, h->i_audio_compression_ratio, h->i_audio_quality, h->i_rtjpeg_quality, h->i_rtjpeg_luma_filter, h->i_rtjpeg_chroma_filter, h->i_lavc_bitrate, h->i_lavc_qmin, h->i_lavc_qmax, h->i_lavc_maxqdiff, h->i_seekable_offset, h->i_keyframe_adjust_offset); *h_ret = h; gst_buffer_unref (buff); return res; }
/** * gst_audio_format_fill_silence: * @info: a #GstAudioFormatInfo * @dest: (array length=length) (element-type guint8): a destination * to fill * @length: the length to fill * * Fill @length bytes in @dest with silence samples for @info. */ void gst_audio_format_fill_silence (const GstAudioFormatInfo * info, gpointer dest, gsize length) { guint8 *dptr = dest; g_return_if_fail (info != NULL); g_return_if_fail (dest != NULL); if (info->flags & GST_AUDIO_FORMAT_FLAG_FLOAT || info->flags & GST_AUDIO_FORMAT_FLAG_SIGNED) { /* float or signed always 0 */ orc_memset (dest, 0, length); } else { gint i, j, bps = info->width >> 3; switch (bps) { case 1: orc_memset (dest, info->silence[0], length); break; case 2:{ #if G_BYTE_ORDER == G_LITTLE_ENDIAN guint16 silence = GST_READ_UINT16_LE (info->silence); #else guint16 silence = GST_READ_UINT16_BE (info->silence); #endif audio_orc_splat_u16 (dest, silence, length / bps); break; } case 4:{ #if G_BYTE_ORDER == G_LITTLE_ENDIAN guint32 silence = GST_READ_UINT32_LE (info->silence); #else guint32 silence = GST_READ_UINT32_BE (info->silence); #endif audio_orc_splat_u32 (dest, silence, length / bps); break; } case 8:{ #if G_BYTE_ORDER == G_LITTLE_ENDIAN guint64 silence = GST_READ_UINT64_LE (info->silence); #else guint64 silence = GST_READ_UINT64_BE (info->silence); #endif audio_orc_splat_u64 (dest, silence, length / bps); break; } default: for (i = 0; i < length; i += bps) { for (j = 0; j < bps; j++) *dptr++ = info->silence[j]; } break; } } }
static GstFlowReturn gst_ivf_parse_handle_frame_data (GstIvfParse * ivf, GstBaseParseFrame * frame, gint * skipsize) { GstBuffer *const buffer = frame->buffer; GstMapInfo map; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *out_buffer; gst_buffer_map (buffer, &map, GST_MAP_READ); if (map.size >= IVF_FILE_HEADER_SIZE) { guint32 frame_size = GST_READ_UINT32_LE (map.data); guint64 frame_pts = GST_READ_UINT64_LE (map.data + 4); GST_LOG_OBJECT (ivf, "Read frame header: size %u, pts %" G_GUINT64_FORMAT, frame_size, frame_pts); if (map.size < IVF_FRAME_HEADER_SIZE + frame_size) { gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (ivf), IVF_FRAME_HEADER_SIZE + frame_size); gst_buffer_unmap (buffer, &map); *skipsize = 0; goto end; } gst_buffer_unmap (buffer, &map); /* Eventually, we would need the buffer memory in a merged state anyway */ out_buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META | GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_MERGE, IVF_FRAME_HEADER_SIZE, frame_size); if (!out_buffer) { GST_ERROR_OBJECT (ivf, "Failed to copy frame buffer"); ret = GST_FLOW_ERROR; *skipsize = IVF_FRAME_HEADER_SIZE + frame_size; goto end; } gst_buffer_replace (&frame->out_buffer, out_buffer); gst_buffer_unref (out_buffer); /* Detect resolution changes on key frames */ if (gst_buffer_map (frame->out_buffer, &map, GST_MAP_READ)) { guint32 width, height; if (ivf->fourcc == GST_MAKE_FOURCC ('V', 'P', '8', '0')) { guint32 frame_tag; frame_tag = GST_READ_UINT24_LE (map.data); if (!(frame_tag & 0x01) && map.size >= 10) { /* key frame */ GST_DEBUG_OBJECT (ivf, "key frame detected"); width = GST_READ_UINT16_LE (map.data + 6) & 0x3fff; height = GST_READ_UINT16_LE (map.data + 8) & 0x3fff; gst_ivf_parse_set_size (ivf, width, height); } } else if (ivf->fourcc == GST_MAKE_FOURCC ('V', 'P', '9', '0')) { /* Fixme: Add vp9 frame header parsing? */ } else if (ivf->fourcc == GST_MAKE_FOURCC ('A', 'V', '0', '1')) { /* Fixme: Add av1 frame header parsing? */ /* This would allow to parse dynamic resolution changes */ /* implement when gstav1parser is ready */ } gst_buffer_unmap (frame->out_buffer, &map); } if (ivf->fps_n > 0) { GST_BUFFER_TIMESTAMP (out_buffer) = gst_util_uint64_scale_int (GST_SECOND * frame_pts, ivf->fps_d, ivf->fps_n); } gst_ivf_parse_update_src_caps (ivf); ret = gst_base_parse_finish_frame (GST_BASE_PARSE_CAST (ivf), frame, IVF_FRAME_HEADER_SIZE + frame_size); *skipsize = 0; } else { GST_LOG_OBJECT (ivf, "Frame data not yet available."); gst_buffer_unmap (buffer, &map); *skipsize = 0; } end: return ret; }
/* chain function * this function does the actual processing */ static GstFlowReturn gst_ivf_parse_chain (GstPad * pad, GstBuffer * buf) { GstIvfParse *ivf = GST_IVF_PARSE (GST_OBJECT_PARENT (pad)); gboolean res; /* lazy creation of the adapter */ if (G_UNLIKELY (ivf->adapter == NULL)) { ivf->adapter = gst_adapter_new (); } GST_LOG_OBJECT (ivf, "Pushing buffer of size %u to adapter", GST_BUFFER_SIZE (buf)); gst_adapter_push (ivf->adapter, buf); /* adapter takes ownership of buf */ res = GST_FLOW_OK; switch (ivf->state) { case GST_IVF_PARSE_START: if (gst_adapter_available (ivf->adapter) >= 32) { GstCaps *caps; const guint8 *data = gst_adapter_peek (ivf->adapter, 32); guint32 magic = GST_READ_UINT32_LE (data); guint16 version = GST_READ_UINT16_LE (data + 4); guint16 header_size = GST_READ_UINT16_LE (data + 6); guint32 fourcc = GST_READ_UINT32_LE (data + 8); guint16 width = GST_READ_UINT16_LE (data + 12); guint16 height = GST_READ_UINT16_LE (data + 14); guint32 rate_num = GST_READ_UINT32_LE (data + 16); guint32 rate_den = GST_READ_UINT32_LE (data + 20); #ifndef GST_DISABLE_GST_DEBUG guint32 num_frames = GST_READ_UINT32_LE (data + 24); #endif /* last 4 bytes unused */ gst_adapter_flush (ivf->adapter, 32); if (magic != GST_MAKE_FOURCC ('D', 'K', 'I', 'F') || version != 0 || header_size != 32 || fourcc != GST_MAKE_FOURCC ('V', 'P', '8', '0')) { GST_ELEMENT_ERROR (ivf, STREAM, WRONG_TYPE, (NULL), (NULL)); return GST_FLOW_ERROR; } /* create src pad caps */ caps = gst_caps_new_simple ("video/x-vp8", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate_num, rate_den, NULL); GST_INFO_OBJECT (ivf, "Found stream: %" GST_PTR_FORMAT, caps); GST_LOG_OBJECT (ivf, "Stream has %d frames", num_frames); gst_pad_set_caps (ivf->srcpad, caps); gst_caps_unref (caps); /* keep framerate in instance for convenience */ ivf->rate_num = rate_num; ivf->rate_den = rate_den; gst_pad_push_event (ivf->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); /* move along */ ivf->state = GST_IVF_PARSE_DATA; } else { GST_LOG_OBJECT (ivf, "Header data not yet available."); break; } /* fall through */ case GST_IVF_PARSE_DATA: while (gst_adapter_available (ivf->adapter) > 12) { const guint8 *data = gst_adapter_peek (ivf->adapter, 12); guint32 frame_size = GST_READ_UINT32_LE (data); guint64 frame_pts = GST_READ_UINT64_LE (data + 4); GST_LOG_OBJECT (ivf, "Read frame header: size %u, pts %" G_GUINT64_FORMAT, frame_size, frame_pts); if (gst_adapter_available (ivf->adapter) >= 12 + frame_size) { GstBuffer *frame; gst_adapter_flush (ivf->adapter, 12); frame = gst_adapter_take_buffer (ivf->adapter, frame_size); gst_buffer_set_caps (frame, GST_PAD_CAPS (ivf->srcpad)); GST_BUFFER_TIMESTAMP (frame) = gst_util_uint64_scale_int (GST_SECOND * frame_pts, ivf->rate_den, ivf->rate_num); GST_BUFFER_DURATION (frame) = gst_util_uint64_scale_int (GST_SECOND, ivf->rate_den, ivf->rate_num); GST_DEBUG_OBJECT (ivf, "Pushing frame of size %u, ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT ", off_end %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (frame), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame)), GST_TIME_ARGS (GST_BUFFER_DURATION (frame)), GST_BUFFER_OFFSET (frame), GST_BUFFER_OFFSET_END (frame)); res = gst_pad_push (ivf->srcpad, frame); if (res != GST_FLOW_OK) break; } else { GST_LOG_OBJECT (ivf, "Frame data not yet available."); break; } } break; default: g_return_val_if_reached (GST_FLOW_ERROR); } return res; }