GstFlowReturn gst_riff_read_chunk (GstElement * element, GstPad * pad, guint64 * _offset, guint32 * tag, GstBuffer ** _chunk_data) { GstBuffer *buf; GstFlowReturn res; guint size; guint64 offset = *_offset; g_return_val_if_fail (element != NULL, GST_FLOW_ERROR); g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR); g_return_val_if_fail (_offset != NULL, GST_FLOW_ERROR); g_return_val_if_fail (tag != NULL, GST_FLOW_ERROR); g_return_val_if_fail (_chunk_data != NULL, GST_FLOW_ERROR); skip_junk: size = 8; if ((res = gst_pad_pull_range (pad, offset, size, &buf)) != GST_FLOW_OK) return res; else if (GST_BUFFER_SIZE (buf) < size) goto too_small; *tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); gst_buffer_unref (buf); GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u", GST_FOURCC_ARGS (*tag), size); /* skip 'JUNK' chunks */ if (*tag == GST_RIFF_TAG_JUNK || *tag == GST_RIFF_TAG_JUNQ) { size = GST_ROUND_UP_2 (size); *_offset += 8 + size; offset += 8 + size; GST_DEBUG_OBJECT (element, "skipping JUNK chunk"); goto skip_junk; } if ((res = gst_pad_pull_range (pad, offset + 8, size, &buf)) != GST_FLOW_OK) return res; else if (GST_BUFFER_SIZE (buf) < size) goto too_small; *_chunk_data = buf; *_offset += 8 + GST_ROUND_UP_2 (size); return GST_FLOW_OK; /* ERRORS */ too_small: { /* short read, we return UNEXPECTED to mark the EOS case */ GST_DEBUG_OBJECT (element, "not enough data (available=%u, needed=%u)", GST_BUFFER_SIZE (buf), size); gst_buffer_unref (buf); return GST_FLOW_UNEXPECTED; } }
static GstFlowReturn gst_ivf_parse_handle_frame_start (GstIvfParse * ivf, GstBaseParseFrame * frame, gint * skipsize) { GstBuffer *const buffer = frame->buffer; GstMapInfo map; GstFlowReturn ret = GST_FLOW_OK; gst_buffer_map (buffer, &map, GST_MAP_READ); if (map.size >= IVF_FILE_HEADER_SIZE) { guint32 magic = GST_READ_UINT32_LE (map.data); guint16 version = GST_READ_UINT16_LE (map.data + 4); guint16 header_size = GST_READ_UINT16_LE (map.data + 6); guint32 fourcc = GST_READ_UINT32_LE (map.data + 8); guint16 width = GST_READ_UINT16_LE (map.data + 12); guint16 height = GST_READ_UINT16_LE (map.data + 14); guint32 fps_n = GST_READ_UINT32_LE (map.data + 16); guint32 fps_d = GST_READ_UINT32_LE (map.data + 20); #ifndef GST_DISABLE_GST_DEBUG guint32 num_frames = GST_READ_UINT32_LE (map.data + 24); #endif if (magic != GST_MAKE_FOURCC ('D', 'K', 'I', 'F') || version != 0 || header_size != 32 || fourcc_to_media_type (fourcc) == NULL) { GST_ELEMENT_ERROR (ivf, STREAM, WRONG_TYPE, (NULL), (NULL)); ret = GST_FLOW_ERROR; goto end; } ivf->fourcc = fourcc; gst_ivf_parse_set_size (ivf, width, height); gst_ivf_parse_set_framerate (ivf, fps_n, fps_d); GST_LOG_OBJECT (ivf, "Stream has %d frames", num_frames); /* move along */ ivf->state = GST_IVF_PARSE_DATA; gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (ivf), IVF_FRAME_HEADER_SIZE); *skipsize = IVF_FILE_HEADER_SIZE; } else { GST_LOG_OBJECT (ivf, "Header data not yet available."); *skipsize = 0; } end: gst_buffer_unmap (buffer, &map); return ret; }
static void convert_line_v210 (GstVideoVBIParser * parser, const guint8 * data) { guint i; guint16 *y = (guint16 *) parser->work_data; guint16 *uv = y + parser->info.width; guint32 a, b, c, d; /* Convert the line */ for (i = 0; i < parser->info.width - 5; i += 6) { a = GST_READ_UINT32_LE (data + (i / 6) * 16 + 0); b = GST_READ_UINT32_LE (data + (i / 6) * 16 + 4); c = GST_READ_UINT32_LE (data + (i / 6) * 16 + 8); d = GST_READ_UINT32_LE (data + (i / 6) * 16 + 12); *uv++ = (a >> 0) & 0x3ff; *y++ = (a >> 10) & 0x3ff; *uv++ = (a >> 20) & 0x3ff; *y++ = (b >> 0) & 0x3ff; *uv++ = (b >> 10) & 0x3ff; *y++ = (b >> 20) & 0x3ff; *uv++ = (c >> 0) & 0x3ff; *y++ = (c >> 10) & 0x3ff; *uv++ = (c >> 20) & 0x3ff; *y++ = (d >> 0) & 0x3ff; *uv++ = (d >> 10) & 0x3ff; *y++ = (d >> 20) & 0x3ff; } if (0) { guint off = 0; gsize length = parser->info.width * 2; GST_TRACE ("--------" "-------------------------------------------------------------------"); while (off < length) { gchar buf[128]; /* gst_info_dump_mem_line will process 16 bytes (8 16bit chunks) at most */ gst_info_dump_mem16_line (buf, sizeof (buf), (guint16 *) parser->work_data, off, length - off); GST_TRACE ("%s", buf); off += 8; } GST_TRACE ("--------" "-------------------------------------------------------------------"); } }
static gboolean parse_exif_tag_header (GstByteReader * reader, gint byte_order, GstExifTagData * _tagdata) { g_assert (_tagdata); /* read the fields */ if (byte_order == G_LITTLE_ENDIAN) { if (!gst_byte_reader_get_uint16_le (reader, &_tagdata->tag) || !gst_byte_reader_get_uint16_le (reader, &_tagdata->tag_type) || !gst_byte_reader_get_uint32_le (reader, &_tagdata->count) || !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) { return FALSE; } _tagdata->offset = GST_READ_UINT32_LE (_tagdata->offset_as_data); } else { if (!gst_byte_reader_get_uint16_be (reader, &_tagdata->tag) || !gst_byte_reader_get_uint16_be (reader, &_tagdata->tag_type) || !gst_byte_reader_get_uint32_be (reader, &_tagdata->count) || !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) { return FALSE; } _tagdata->offset = GST_READ_UINT32_BE (_tagdata->offset_as_data); } return TRUE; }
static gpointer make_alac_magic_cookie (GstBuffer * codec_data, gsize * len) { guint8 *res; if (GST_BUFFER_SIZE (codec_data) < 4) return NULL; *len = 20 + GST_BUFFER_SIZE (codec_data); res = g_malloc0 (*len); /* 12 first bytes are 'frma' (format) atom with 'alac' value */ GST_WRITE_UINT32_BE (res, 0xc); /* Atom length: 12 bytes */ GST_WRITE_UINT32_LE (res + 4, QT_MAKE_FOURCC_BE ('f', 'r', 'm', 'a')); GST_WRITE_UINT32_LE (res + 8, QT_MAKE_FOURCC_BE ('a', 'l', 'a', 'c')); /* Write the codec_data, but with the first four bytes reversed (different endianness). This is the 'alac' atom. */ GST_WRITE_UINT32_BE (res + 12, GST_READ_UINT32_LE (GST_BUFFER_DATA (codec_data))); memcpy (res + 16, GST_BUFFER_DATA (codec_data) + 4, GST_BUFFER_SIZE (codec_data) - 4); /* Terminator atom */ GST_WRITE_UINT32_BE (res + 12 + GST_BUFFER_SIZE (codec_data), 8); GST_WRITE_UINT32_BE (res + 12 + GST_BUFFER_SIZE (codec_data) + 4, 0); 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 gboolean gst_aiff_parse_parse_comm (GstAiffParse * aiff, GstBuffer * buf) { guint8 *data; int size; if (aiff->is_aifc) size = 22; else size = 18; if (GST_BUFFER_SIZE (buf) < size) { GST_WARNING_OBJECT (aiff, "COMM chunk too short, cannot parse header"); return FALSE; } data = GST_BUFFER_DATA (buf); aiff->channels = GST_READ_UINT16_BE (data); aiff->total_frames = GST_READ_UINT32_BE (data + 2); aiff->depth = GST_READ_UINT16_BE (data + 6); aiff->width = GST_ROUND_UP_8 (aiff->depth); aiff->rate = (int) gst_aiff_parse_read_IEEE80 (data + 8); if (aiff->is_aifc) { /* We only support the 'trivial' uncompressed AIFC, but it can be * either big or little endian */ if (GST_READ_UINT32_LE (data + 18) == GST_MAKE_FOURCC ('N', 'O', 'N', 'E')) aiff->endianness = G_BIG_ENDIAN; else if (GST_READ_UINT32_LE (data + 18) == GST_MAKE_FOURCC ('s', 'o', 'w', 't')) aiff->endianness = G_LITTLE_ENDIAN; else { GST_WARNING_OBJECT (aiff, "Unsupported compression in AIFC " "file: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (GST_READ_UINT32_LE (data + 18))); return FALSE; } } else aiff->endianness = G_BIG_ENDIAN; return TRUE; }
static GstFlowReturn mxf_d10_sound_handle_essence_element (const MXFUL * key, GstBuffer * buffer, GstCaps * caps, MXFMetadataTimelineTrack * track, MXFMetadataSourceClip * component, gpointer mapping_data, GstBuffer ** outbuf) { guint i, j, nsamples; const guint8 *indata; guint8 *outdata; MXFD10AudioMappingData *data = mapping_data; g_return_val_if_fail (data != NULL, GST_FLOW_ERROR); g_return_val_if_fail (data->channels != 0 && data->width != 0, GST_FLOW_ERROR); /* SMPTE 386M 5.3.1 */ if (key->u[12] != 0x06 || key->u[13] != 0x01 || key->u[14] != 0x10) { GST_ERROR ("Invalid D10 sound essence element"); return GST_FLOW_ERROR; } /* Now transform raw AES3 into raw audio, see SMPTE 331M */ if ((GST_BUFFER_SIZE (buffer) - 4) % 32 != 0) { GST_ERROR ("Invalid D10 sound essence buffer size"); return GST_FLOW_ERROR; } nsamples = ((GST_BUFFER_SIZE (buffer) - 4) / 4) / 8; *outbuf = gst_buffer_new_and_alloc (nsamples * data->width * data->channels); gst_buffer_copy_metadata (*outbuf, buffer, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_CAPS); indata = GST_BUFFER_DATA (buffer); outdata = GST_BUFFER_DATA (*outbuf); /* Skip 32 bit header */ indata += 4; for (i = 0; i < nsamples; i++) { for (j = 0; j < data->channels; j++) { guint32 in = GST_READ_UINT32_LE (indata); /* Remove first 4 and last 4 bits as they only * contain status data. Shift the 24 bit samples * to the correct width afterwards. */ if (data->width == 2) { in = (in >> 12) & 0xffff; GST_WRITE_UINT16_LE (outdata, in); } else if (data->width == 3) { in = (in >> 4) & 0xffffff; GST_WRITE_UINT24_LE (outdata, in); }
/** * gst_riff_parse_file_header: * @element: caller element (used for debugging/error). * @buf: input buffer from which the file header will be parsed, * should be at least 12 bytes long. * @doctype: a fourcc (returned by this function) to indicate the * type of document (according to the header). * * Reads the first few bytes from the provided buffer, checks * if this stream is a RIFF stream, and determines document type. * This function takes ownership of @buf so it should not be used anymore * after calling this function. * * Returns: FALSE if this is not a RIFF stream (in which case the * caller should error out; we already throw an error), or TRUE * if it is. */ gboolean gst_riff_parse_file_header (GstElement * element, GstBuffer * buf, guint32 * doctype) { guint8 *data; guint32 tag; g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (doctype != NULL, FALSE); if (GST_BUFFER_SIZE (buf) < 12) goto too_small; data = GST_BUFFER_DATA (buf); tag = GST_READ_UINT32_LE (data); if (tag != GST_RIFF_TAG_RIFF && tag != GST_RIFF_TAG_AVF0) goto not_riff; *doctype = GST_READ_UINT32_LE (data + 8); gst_buffer_unref (buf); return TRUE; /* ERRORS */ too_small: { GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL), ("Not enough data to parse RIFF header (%d available, %d needed)", GST_BUFFER_SIZE (buf), 12)); gst_buffer_unref (buf); return FALSE; } not_riff: { GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL), ("Stream is no RIFF stream: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); gst_buffer_unref (buf); return FALSE; } }
static gboolean read_atom_header (FILE * f, guint32 * fourcc, guint32 * size) { guint8 aux[8]; if (fread (aux, 1, 8, f) != 8) return FALSE; *size = GST_READ_UINT32_BE (aux); *fourcc = GST_READ_UINT32_LE (aux + 4); return TRUE; }
static gboolean gst_aiff_parse_parse_file_header (GstAiffParse * aiff, GstBuffer * buf) { guint8 *data; guint32 header, type = 0; if (GST_BUFFER_SIZE (buf) < 12) { GST_WARNING_OBJECT (aiff, "Buffer too short"); goto not_aiff; } data = GST_BUFFER_DATA (buf); header = GST_READ_UINT32_LE (data); type = GST_READ_UINT32_LE (data + 8); if (header != GST_MAKE_FOURCC ('F', 'O', 'R', 'M')) goto not_aiff; if (type == GST_MAKE_FOURCC ('A', 'I', 'F', 'F')) aiff->is_aifc = FALSE; else if (type == GST_MAKE_FOURCC ('A', 'I', 'F', 'C')) aiff->is_aifc = TRUE; else goto not_aiff; gst_buffer_unref (buf); return TRUE; /* ERRORS */ not_aiff: { GST_ELEMENT_ERROR (aiff, STREAM, WRONG_TYPE, (NULL), ("File is not an AIFF file: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (type))); gst_buffer_unref (buf); return FALSE; } }
/* FrameHeaderLoad: */ static GstFlowReturn gst_nuv_demux_frame_header_load (GstNuvDemux * nuv, nuv_frame_header ** h_ret) { unsigned char *data; nuv_frame_header *h; GstBuffer *buf = NULL; GstFlowReturn res = gst_nuv_demux_read_bytes (nuv, 12, TRUE, &buf); if (res != GST_FLOW_OK) { if (buf != NULL) { gst_buffer_unref (buf); } return res; } h = g_new0 (nuv_frame_header, 1); data = buf->data; h->i_type = data[0]; h->i_compression = data[1]; h->i_keyframe = data[2]; h->i_filters = data[3]; h->i_timecode = GST_READ_UINT32_LE (&data[4]); h->i_length = GST_READ_UINT32_LE (&data[8]); GST_DEBUG_OBJECT (nuv, "frame hdr: t=%c c=%c k=%d f=0x%x timecode=%d l=%d", h->i_type, h->i_compression ? h->i_compression : ' ', h->i_keyframe ? h->i_keyframe : ' ', h->i_filters, h->i_timecode, h->i_length); *h_ret = h; gst_buffer_unref (buf); return GST_FLOW_OK; }
static gboolean get_next_chunk (GstAdapter *adapter, Chunk *chunk) { const guint8 *data; guint length; data = gst_adapter_peek (adapter, 8); if (!data) return FALSE; length = GST_READ_UINT32_BE (data + 4); chunk->fourcc = GST_READ_UINT32_LE (data); chunk->length = length; gst_adapter_flush (adapter, 8); chunk->data = gst_adapter_peek (adapter, gst_adapter_available_fast (adapter)); chunk->available = gst_adapter_available_fast (adapter); return TRUE; }
static gboolean gst_ape_demux_identify_tag (GstTagDemux * demux, GstBuffer * buffer, gboolean start_tag, guint * tag_size) { if (memcmp (GST_BUFFER_DATA (buffer), "APETAGEX", 8) != 0) { GST_DEBUG_OBJECT (demux, "No APETAGEX marker at %s - not an APE file", (start_tag) ? "start" : "end"); return FALSE; } *tag_size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buffer) + 12); /* size is without header, so add 32 to account for that */ *tag_size += 32; return TRUE; }
/* * gst_aiffparse_peek_chunk_info: * @aiff AIFFparse object * @tag holder for tag * @size holder for tag size * * Peek next chunk info (tag and size) * * Returns: %TRUE when the chunk info (header) is available */ static gboolean gst_aiffparse_peek_chunk_info (AIFFParse * aiff, guint32 * tag, guint32 * size) { const guint8 *data = NULL; if (gst_adapter_available (aiff->adapter) < 8) return FALSE; data = gst_adapter_peek (aiff->adapter, 8); *tag = GST_READ_UINT32_LE (data); *size = GST_READ_UINT32_BE (data + 4); GST_DEBUG ("Next chunk size is %d bytes, type %" GST_FOURCC_FORMAT, *size, GST_FOURCC_ARGS (*tag)); return TRUE; }
/* HeaderLoad: */ static GstFlowReturn gst_nuv_demux_header_load (GstNuvDemux * nuv, nuv_header ** h_ret) { GstBuffer *buffer = NULL; GstFlowReturn res; nuv_header *h; res = gst_nuv_demux_read_bytes (nuv, 72, TRUE, &buffer); if (res != GST_FLOW_OK) return res; h = g_new0 (nuv_header, 1); memcpy (h->id, buffer->data, 12); memcpy (h->version, buffer->data + 12, 5); h->i_width = GST_READ_UINT32_LE (&buffer->data[20]); h->i_height = GST_READ_UINT32_LE (&buffer->data[24]); h->i_width_desired = GST_READ_UINT32_LE (&buffer->data[28]); h->i_height_desired = GST_READ_UINT32_LE (&buffer->data[32]); h->i_mode = buffer->data[36]; h->d_aspect = READ_DOUBLE_FROM_LE (&buffer->data[40]); h->d_fps = READ_DOUBLE_FROM_LE (&buffer->data[48]); h->i_video_blocks = GST_READ_UINT32_LE (&buffer->data[56]); h->i_audio_blocks = GST_READ_UINT32_LE (&buffer->data[60]); h->i_text_blocks = GST_READ_UINT32_LE (&buffer->data[64]); h->i_keyframe_distance = GST_READ_UINT32_LE (&buffer->data[68]); GST_DEBUG_OBJECT (nuv, "nuv: h=%s v=%s %dx%d a=%f fps=%f v=%d a=%d t=%d kfd=%d", h->id, h->version, h->i_width, h->i_height, h->d_aspect, h->d_fps, h->i_video_blocks, h->i_audio_blocks, h->i_text_blocks, h->i_keyframe_distance); *h_ret = h; gst_buffer_unref (buffer); return res; }
static GstFlowReturn gst_aiff_parse_read_chunk (GstAiffParse * aiff, guint64 * offset, guint32 * tag, GstBuffer ** data) { guint size; GstFlowReturn res; GstBuffer *buf; if ((res = gst_pad_pull_range (aiff->sinkpad, *offset, 8, &buf)) != GST_FLOW_OK) return res; *tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4); if ((res = gst_pad_pull_range (aiff->sinkpad, (*offset) + 8, size, &buf)) != GST_FLOW_OK) return res; else if (GST_BUFFER_SIZE (buf) < size) goto too_small; *data = buf; *offset += 8 + GST_ROUND_UP_2 (size); return GST_FLOW_OK; /* ERRORS */ too_small: { /* short read, we return UNEXPECTED to mark the EOS case */ GST_DEBUG_OBJECT (aiff, "not enough data (available=%u, needed=%u)", GST_BUFFER_SIZE (buf), size); gst_buffer_unref (buf); return GST_FLOW_UNEXPECTED; } }
/* we are unlikely to deal with lengths > 2GB here any time soon, so just * return a signed int and use that for error reporting */ static inline gint asf_packet_read_varlen_int (guint lentype_flags, guint lentype_bit_offset, const guint8 ** p_data, guint * p_size) { static const guint lens[4] = { 0, 1, 2, 4 }; guint len, val; len = lens[(lentype_flags >> lentype_bit_offset) & 0x03]; /* will make caller bail out with a short read if there's not enough data */ if (G_UNLIKELY (*p_size < len)) { GST_WARNING ("need %u bytes, but only %u bytes available", len, *p_size); return -1; } switch (len) { case 0: val = 0; break; case 1: val = GST_READ_UINT8 (*p_data); break; case 2: val = GST_READ_UINT16_LE (*p_data); break; case 4: val = GST_READ_UINT32_LE (*p_data); break; default: g_assert_not_reached (); } *p_data += len; *p_size -= len; return (gint) val; }
/* Correctly format samples with width!=depth for the wav format, i.e. * have the data in the highest depth bits and all others zero */ static void gst_wavenc_format_samples (GstBuffer * buf, guint width, guint depth) { guint8 *data = GST_BUFFER_DATA (buf); guint nsamples = (GST_BUFFER_SIZE (buf) * 8) / width; guint32 tmp; for (; nsamples; nsamples--) { switch (width) { case 8: tmp = *data; *data = *data << (width - depth); data += 1; break; case 16: tmp = GST_READ_UINT16_LE (data); tmp = tmp << (width - depth); GST_WRITE_UINT16_LE (data, tmp); data += 2; break; case 24: tmp = READ24_FROM_LE (data); tmp = tmp << (width - depth); WRITE24_TO_LE (data, tmp); data += 3; break; case 32: tmp = GST_READ_UINT32_LE (data); tmp = tmp << (width - depth); GST_WRITE_UINT32_LE (data, tmp); data += 4; break; } } }
static gboolean gst_ogg_avi_parse_setcaps (GstPad * pad, GstCaps * caps) { GstOggAviParse *ogg; GstStructure *structure; const GValue *codec_data; GstBuffer *buffer; GstMapInfo map; guint8 *ptr; gsize left; guint32 sizes[3]; GstCaps *outcaps; gint i, offs; ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad)); structure = gst_caps_get_structure (caps, 0); /* take codec data */ codec_data = gst_structure_get_value (structure, "codec_data"); if (codec_data == NULL) goto no_data; /* only buffers are valid */ if (G_VALUE_TYPE (codec_data) != GST_TYPE_BUFFER) goto wrong_format; /* Now parse the data */ buffer = gst_value_get_buffer (codec_data); /* first 22 bytes are bits_per_sample, channel_mask, GUID * Then we get 3 LE guint32 with the 3 header sizes * then we get the bytes of the 3 headers. */ gst_buffer_map (buffer, &map, GST_MAP_READ); ptr = map.data; left = map.size; GST_LOG_OBJECT (ogg, "configuring codec_data of size %" G_GSIZE_FORMAT, left); /* skip headers */ ptr += 22; left -= 22; /* we need at least 12 bytes for the packet sizes of the 3 headers */ if (left < 12) goto buffer_too_small; /* read sizes of the 3 headers */ sizes[0] = GST_READ_UINT32_LE (ptr); sizes[1] = GST_READ_UINT32_LE (ptr + 4); sizes[2] = GST_READ_UINT32_LE (ptr + 8); GST_DEBUG_OBJECT (ogg, "header sizes: %u %u %u", sizes[0], sizes[1], sizes[2]); left -= 12; /* and we need at least enough data for all the headers */ if (left < sizes[0] + sizes[1] + sizes[2]) goto buffer_too_small; /* set caps */ outcaps = gst_caps_new_empty_simple ("audio/x-vorbis"); gst_pad_set_caps (ogg->srcpad, outcaps); gst_caps_unref (outcaps); /* copy header data */ offs = 34; for (i = 0; i < 3; i++) { GstBuffer *out; /* now output the raw vorbis header packets */ out = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offs, sizes[i]); gst_pad_push (ogg->srcpad, out); offs += sizes[i]; } gst_buffer_unmap (buffer, &map); return TRUE; /* ERRORS */ no_data: { GST_DEBUG_OBJECT (ogg, "no codec_data found in caps"); return FALSE; } wrong_format: { GST_DEBUG_OBJECT (ogg, "codec_data is not a buffer"); return FALSE; } buffer_too_small: { GST_DEBUG_OBJECT (ogg, "codec_data is too small"); gst_buffer_unmap (buffer, &map); return FALSE; } }
/** * gst_riff_parse_chunk: * @element: caller element (used for debugging). * @buf: input buffer. * @offset: offset in the buffer in the caller. Is incremented * by the read size by this function. * @fourcc: fourcc (returned by this function0 of the chunk. * @chunk_data: buffer (returned by the function) containing the * chunk data, which may be NULL if chunksize == 0 * * Reads a single chunk. * * Returns: FALSE on error, TRUE otherwise */ gboolean gst_riff_parse_chunk (GstElement * element, GstBuffer * buf, guint * _offset, guint32 * _fourcc, GstBuffer ** chunk_data) { guint size, bufsize; guint32 fourcc; guint8 *data; guint offset = *_offset; g_return_val_if_fail (element != NULL, FALSE); g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (_offset != NULL, FALSE); g_return_val_if_fail (_fourcc != NULL, FALSE); g_return_val_if_fail (chunk_data != NULL, FALSE); *chunk_data = NULL; *_fourcc = 0; bufsize = GST_BUFFER_SIZE (buf); if (bufsize == offset) goto end_offset; if (bufsize < offset + 8) goto too_small; /* read header */ data = GST_BUFFER_DATA (buf) + offset; fourcc = GST_READ_UINT32_LE (data); size = GST_READ_UINT32_LE (data + 4); GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u", GST_FOURCC_ARGS (fourcc), size); /* be paranoid: size may be nonsensical value here, such as (guint) -1 */ if (G_UNLIKELY (size > G_MAXINT)) goto bogus_size; if (bufsize < size + 8 + offset) { GST_DEBUG_OBJECT (element, "Needed chunk data (%d) is more than available (%d), shortcutting", size, bufsize - 8 - offset); size = bufsize - 8 - offset; } if (size) *chunk_data = gst_buffer_create_sub (buf, offset + 8, size); else *chunk_data = NULL; *_fourcc = fourcc; *_offset += 8 + GST_ROUND_UP_2 (size); return TRUE; /* ERRORS */ end_offset: { GST_DEBUG_OBJECT (element, "End of chunk (offset %d)", offset); return FALSE; } too_small: { GST_DEBUG_OBJECT (element, "Failed to parse chunk header (offset %d, %d available, %d needed)", offset, bufsize, 8); return FALSE; } bogus_size: { GST_ERROR_OBJECT (element, "Broken file: bogus chunk size %u", size); return FALSE; } }
/** * gst_riff_parse_info: * @element: caller element (used for debugging/error). * @buf: input data to be used for parsing, stripped from header. * @taglist: a pointer to a taglist (returned by this function) * containing information about this stream. May be * NULL if no supported tags were found. * * Parses stream metadata from input data. */ void gst_riff_parse_info (GstElement * element, GstBuffer * buf, GstTagList ** _taglist) { guint8 *data; guint size, tsize; guint32 tag; const gchar *type; GstTagList *taglist; g_return_if_fail (_taglist != NULL); if (!buf) { *_taglist = NULL; return; } data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); taglist = gst_tag_list_new (); while (size > 8) { tag = GST_READ_UINT32_LE (data); tsize = GST_READ_UINT32_LE (data + 4); size -= 8; data += 8; GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u", GST_FOURCC_ARGS (tag), tsize); if (tsize > size) { GST_WARNING_OBJECT (element, "Tagsize %d is larger than available data %d", tsize, size); tsize = size; } /* find out the type of metadata */ switch (tag) { case GST_RIFF_INFO_IARL: type = GST_TAG_LOCATION; break; case GST_RIFF_INFO_IART: type = GST_TAG_ARTIST; break; case GST_RIFF_INFO_ICMS: type = NULL; /*"Commissioner"; */ break; case GST_RIFF_INFO_ICMT: type = GST_TAG_COMMENT; break; case GST_RIFF_INFO_ICOP: type = GST_TAG_COPYRIGHT; break; case GST_RIFF_INFO_ICRD: type = GST_TAG_DATE; break; case GST_RIFF_INFO_ICRP: type = NULL; /*"Cropped"; */ break; case GST_RIFF_INFO_IDIM: type = NULL; /*"Dimensions"; */ break; case GST_RIFF_INFO_IDPI: type = NULL; /*"Dots per Inch"; */ break; case GST_RIFF_INFO_IENG: type = NULL; /*"Engineer"; */ break; case GST_RIFF_INFO_IGNR: type = GST_TAG_GENRE; break; case GST_RIFF_INFO_IKEY: type = GST_TAG_KEYWORDS; break; case GST_RIFF_INFO_ILGT: type = NULL; /*"Lightness"; */ break; case GST_RIFF_INFO_IMED: type = NULL; /*"Medium"; */ break; case GST_RIFF_INFO_INAM: type = GST_TAG_TITLE; break; case GST_RIFF_INFO_IPLT: type = NULL; /*"Palette"; */ break; case GST_RIFF_INFO_IPRD: type = NULL; /*"Product"; */ break; case GST_RIFF_INFO_ISBJ: type = NULL; /*"Subject"; */ break; case GST_RIFF_INFO_ISFT: type = GST_TAG_ENCODER; break; case GST_RIFF_INFO_ISHP: type = NULL; /*"Sharpness"; */ break; case GST_RIFF_INFO_ISRC: type = GST_TAG_ISRC; break; case GST_RIFF_INFO_ISRF: type = NULL; /*"Source Form"; */ break; case GST_RIFF_INFO_ITCH: type = NULL; /*"Technician"; */ break; default: type = NULL; GST_WARNING_OBJECT (element, "Unknown INFO (metadata) tag entry %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)); break; } if (type != NULL && data[0] != '\0') { static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING", "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; gchar *val; val = gst_tag_freeform_string_to_utf8 ((gchar *) data, tsize, env_vars); if (val) { gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL); g_free (val); } else { GST_WARNING_OBJECT (element, "could not extract %s tag", type); } } if (tsize & 1) { tsize++; if (tsize > size) tsize = size; } data += tsize; size -= tsize; } if (!gst_tag_list_is_empty (taglist)) { *_taglist = taglist; } else { *_taglist = NULL; gst_tag_list_free (taglist); } return; }
static gboolean gst_rtp_speex_pay_parse_ident (GstRtpSPEEXPay * rtpspeexpay, const guint8 * data, guint size) { guint32 version, header_size, rate, mode, nb_channels; GstBaseRTPPayload *payload; gchar *cstr; gboolean res; /* we need the header string (8), the version string (20), the version * and the header length. */ if (size < 36) goto too_small; if (!g_str_has_prefix ((const gchar *) data, "Speex ")) goto wrong_header; /* skip header and version string */ data += 28; version = GST_READ_UINT32_LE (data); if (version != 1) goto wrong_version; data += 4; /* ensure sizes */ header_size = GST_READ_UINT32_LE (data); if (header_size < 80) goto header_too_small; if (size < header_size) goto payload_too_small; data += 4; rate = GST_READ_UINT32_LE (data); data += 4; mode = GST_READ_UINT32_LE (data); data += 8; nb_channels = GST_READ_UINT32_LE (data); GST_DEBUG_OBJECT (rtpspeexpay, "rate %d, mode %d, nb_channels %d", rate, mode, nb_channels); payload = GST_BASE_RTP_PAYLOAD (rtpspeexpay); gst_basertppayload_set_options (payload, "audio", FALSE, "SPEEX", rate); cstr = g_strdup_printf ("%d", nb_channels); res = gst_basertppayload_set_outcaps (payload, "encoding-params", G_TYPE_STRING, cstr, NULL); g_free (cstr); return res; /* ERRORS */ too_small: { GST_DEBUG_OBJECT (rtpspeexpay, "ident packet too small, need at least 32 bytes"); return FALSE; } wrong_header: { GST_DEBUG_OBJECT (rtpspeexpay, "ident packet does not start with \"Speex \""); return FALSE; } wrong_version: { GST_DEBUG_OBJECT (rtpspeexpay, "can only handle version 1, have version %d", version); return FALSE; } header_too_small: { GST_DEBUG_OBJECT (rtpspeexpay, "header size too small, need at least 80 bytes, " "got only %d", header_size); return FALSE; } payload_too_small: { GST_DEBUG_OBJECT (rtpspeexpay, "payload too small, need at least %d bytes, got only %d", header_size, size); return FALSE; } }
static gboolean gst_rtp_celt_pay_parse_ident (GstRtpCELTPay * rtpceltpay, const guint8 * data, guint size) { guint32 version, header_size, rate, nb_channels, frame_size, overlap; guint32 bytes_per_packet; GstBaseRTPPayload *payload; gchar *cstr, *fsstr; gboolean res; /* we need the header string (8), the version string (20), the version * and the header length. */ if (size < 36) goto too_small; if (!g_str_has_prefix ((const gchar *) data, "CELT ")) goto wrong_header; /* skip header and version string */ data += 28; version = GST_READ_UINT32_LE (data); GST_DEBUG_OBJECT (rtpceltpay, "version %08x", version); #if 0 if (version != 1) goto wrong_version; #endif data += 4; /* ensure sizes */ header_size = GST_READ_UINT32_LE (data); if (header_size < 56) goto header_too_small; if (size < header_size) goto payload_too_small; data += 4; rate = GST_READ_UINT32_LE (data); data += 4; nb_channels = GST_READ_UINT32_LE (data); data += 4; frame_size = GST_READ_UINT32_LE (data); data += 4; overlap = GST_READ_UINT32_LE (data); data += 4; bytes_per_packet = GST_READ_UINT32_LE (data); GST_DEBUG_OBJECT (rtpceltpay, "rate %d, nb_channels %d, frame_size %d", rate, nb_channels, frame_size); GST_DEBUG_OBJECT (rtpceltpay, "overlap %d, bytes_per_packet %d", overlap, bytes_per_packet); payload = GST_BASE_RTP_PAYLOAD (rtpceltpay); gst_basertppayload_set_options (payload, "audio", FALSE, "CELT", rate); cstr = g_strdup_printf ("%d", nb_channels); fsstr = g_strdup_printf ("%d", frame_size); res = gst_basertppayload_set_outcaps (payload, "encoding-params", G_TYPE_STRING, cstr, "frame-size", G_TYPE_STRING, fsstr, NULL); g_free (cstr); g_free (fsstr); return res; /* ERRORS */ too_small: { GST_DEBUG_OBJECT (rtpceltpay, "ident packet too small, need at least 32 bytes"); return FALSE; } wrong_header: { GST_DEBUG_OBJECT (rtpceltpay, "ident packet does not start with \"CELT \""); return FALSE; } #if 0 wrong_version: { GST_DEBUG_OBJECT (rtpceltpay, "can only handle version 1, have version %d", version); return FALSE; } #endif header_too_small: { GST_DEBUG_OBJECT (rtpceltpay, "header size too small, need at least 80 bytes, " "got only %d", header_size); return FALSE; } payload_too_small: { GST_DEBUG_OBJECT (rtpceltpay, "payload too small, need at least %d bytes, got only %d", header_size, size); return FALSE; } }
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; }
static GstFlowReturn gst_avi_subtitle_parse_gab2_chunk (GstAviSubtitle * sub, GstBuffer * buf) { const guint8 *data; gchar *name_utf8; guint name_length; guint file_length; guint size; data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); /* check the magic word "GAB2\0", and the next word must be 2 */ if (size < 12 || memcmp (data, "GAB2\0\2\0", 5 + 2) != 0) goto wrong_magic_word; /* read 'name' of subtitle */ name_length = GST_READ_UINT32_LE (data + 5 + 2); GST_LOG_OBJECT (sub, "length of name: %u", name_length); if (size <= 17 + name_length) goto wrong_name_length; name_utf8 = g_convert ((gchar *) data + 11, name_length, "UTF-8", "UTF-16LE", NULL, NULL, NULL); if (name_utf8) { GST_LOG_OBJECT (sub, "subtitle name: %s", name_utf8); gst_avi_subtitle_title_tag (sub, name_utf8); g_free (name_utf8); } /* next word must be 4 */ if (GST_READ_UINT16_LE (data + 11 + name_length) != 0x4) goto wrong_fixed_word_2; file_length = GST_READ_UINT32_LE (data + 13 + name_length); GST_LOG_OBJECT (sub, "length srt/ssa file: %u", file_length); if (size < (17 + name_length + file_length)) goto wrong_total_length; /* store this, so we can send it again after a seek; note that we shouldn't * assume all the remaining data in the chunk is subtitle data, there may * be padding at the end for some reason, so only parse file_length bytes */ sub->subfile = gst_avi_subtitle_extract_file (sub, buf, 17 + name_length, file_length); if (sub->subfile == NULL) goto extract_failed; return GST_FLOW_OK; /* ERRORS */ wrong_magic_word: { GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), ("Wrong magic word")); return GST_FLOW_ERROR; } wrong_name_length: { GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), ("name doesn't fit in buffer (%d < %d)", size, 17 + name_length)); return GST_FLOW_ERROR; } wrong_fixed_word_2: { GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), ("wrong fixed word: expected %u, got %u", 4, GST_READ_UINT16_LE (data + 11 + name_length))); return GST_FLOW_ERROR; } wrong_total_length: { GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), ("buffer size is wrong: need %d bytes, have %d bytes", 17 + name_length + file_length, size)); return GST_FLOW_ERROR; } extract_failed: { GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), ("could not extract subtitles")); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_aiff_parse_stream_headers (GstAiffParse * aiff) { GstFlowReturn res; GstBuffer *buf; guint32 tag, size; gboolean gotdata = FALSE; gboolean done = FALSE; GstEvent **event_p; GstFormat bformat; gint64 upstream_size = 0; bformat = GST_FORMAT_BYTES; gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size); GST_DEBUG_OBJECT (aiff, "upstream size %" G_GUINT64_FORMAT, upstream_size); /* loop headers until we get data */ while (!done) { if (aiff->streaming) { if (!gst_aiff_parse_peek_chunk_info (aiff, &tag, &size)) return GST_FLOW_OK; } else { if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset, 8, &buf)) != GST_FLOW_OK) goto header_read_error; tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4); } GST_INFO_OBJECT (aiff, "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (tag), aiff->offset); /* We just keep reading chunks until we find the one we're interested in. */ switch (tag) { case GST_MAKE_FOURCC ('C', 'O', 'M', 'M'):{ if (aiff->streaming) { if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size)) return GST_FLOW_OK; gst_adapter_flush (aiff->adapter, 8); aiff->offset += 8; buf = gst_adapter_take_buffer (aiff->adapter, size); } else { if ((res = gst_aiff_parse_read_chunk (aiff, &aiff->offset, &tag, &buf)) != GST_FLOW_OK) return res; } if (!gst_aiff_parse_parse_comm (aiff, buf)) { gst_buffer_unref (buf); goto parse_header_error; } gst_buffer_unref (buf); /* do sanity checks of header fields */ if (aiff->channels == 0) goto no_channels; if (aiff->rate == 0) goto no_rate; GST_DEBUG_OBJECT (aiff, "creating the caps"); aiff->caps = gst_aiff_parse_create_caps (aiff); if (!aiff->caps) goto unknown_format; gst_pad_set_caps (aiff->srcpad, aiff->caps); aiff->bytes_per_sample = aiff->channels * aiff->width / 8; aiff->bps = aiff->bytes_per_sample * aiff->rate; if (aiff->bytes_per_sample <= 0) goto no_bytes_per_sample; aiff->got_comm = TRUE; break; } case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{ GstFormat fmt; GstBuffer *ssndbuf = NULL; const guint8 *ssnddata = NULL; guint32 datasize; GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size); /* Now, read the 8-byte header in the SSND chunk */ if (aiff->streaming) { if (!gst_aiff_parse_peek_data (aiff, 16, &ssnddata)) return GST_FLOW_OK; } else { gst_buffer_unref (buf); if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset, 16, &ssndbuf)) != GST_FLOW_OK) goto header_read_error; ssnddata = GST_BUFFER_DATA (ssndbuf); } aiff->ssnd_offset = GST_READ_UINT32_BE (ssnddata + 8); aiff->ssnd_blocksize = GST_READ_UINT32_BE (ssnddata + 12); gotdata = TRUE; if (aiff->streaming) { gst_adapter_flush (aiff->adapter, 16); } else { gst_buffer_unref (ssndbuf); } /* 8 byte chunk header, 16 byte SSND header */ aiff->offset += 24; datasize = size - 16; aiff->datastart = aiff->offset + aiff->ssnd_offset; /* file might be truncated */ fmt = GST_FORMAT_BYTES; if (upstream_size) { size = MIN (datasize, (upstream_size - aiff->datastart)); } aiff->datasize = (guint64) datasize; aiff->dataleft = (guint64) datasize; aiff->end_offset = datasize + aiff->datastart; if (!aiff->streaming) { /* We will continue looking at chunks until the end - to read tags, * etc. */ aiff->offset += datasize; } GST_DEBUG_OBJECT (aiff, "datasize = %d", datasize); if (aiff->streaming) { done = TRUE; } break; } default: gst_aiff_parse_ignore_chunk (aiff, buf, tag, size); } if (upstream_size && (aiff->offset >= upstream_size)) { /* Now we have gone through the whole file */ done = TRUE; } } /* We read all the chunks (in pull mode) or reached the SSND chunk * (in push mode). We must have both COMM and SSND now; error out * otherwise. */ if (!aiff->got_comm) { GST_WARNING_OBJECT (aiff, "Failed to find COMM chunk"); goto no_header; } if (!gotdata) { GST_WARNING_OBJECT (aiff, "Failed to find SSND chunk"); goto no_data; } GST_DEBUG_OBJECT (aiff, "Finished parsing headers"); if (gst_aiff_parse_calculate_duration (aiff)) { gst_segment_init (&aiff->segment, GST_FORMAT_TIME); gst_segment_set_duration (&aiff->segment, GST_FORMAT_TIME, aiff->duration); } else { /* no bitrate, let downstream peer do the math, we'll feed it bytes. */ gst_segment_init (&aiff->segment, GST_FORMAT_BYTES); gst_segment_set_duration (&aiff->segment, GST_FORMAT_BYTES, aiff->datasize); } /* now we have all the info to perform a pending seek if any, if no * event, this will still do the right thing and it will also send * the right newsegment event downstream. */ gst_aiff_parse_perform_seek (aiff, aiff->seek_event); /* remove pending event */ event_p = &aiff->seek_event; gst_event_replace (event_p, NULL); /* we just started, we are discont */ aiff->discont = TRUE; aiff->state = AIFF_PARSE_DATA; return GST_FLOW_OK; /* ERROR */ no_header: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("Invalid AIFF header (no COMM found)")); return GST_FLOW_ERROR; } no_data: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("Invalid AIFF: no SSND found")); return GST_FLOW_ERROR; } parse_header_error: { GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL), ("Couldn't parse audio header")); return GST_FLOW_ERROR; } no_channels: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Stream claims to contain no channels - invalid data")); return GST_FLOW_ERROR; } no_rate: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Stream with sample_rate == 0 - invalid data")); return GST_FLOW_ERROR; } no_bytes_per_sample: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Could not caluclate bytes per sample - invalid data")); return GST_FLOW_ERROR; } unknown_format: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("No caps found for format 0x%x, %d channels, %d Hz", aiff->format, aiff->channels, aiff->rate)); return GST_FLOW_ERROR; } header_read_error: { GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL), ("Couldn't read in header")); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) { const guint8 *data; GstAudioChannelPosition pos[64]; const GstAudioChannelPosition *posn = NULL; GstMapInfo map; if (!gst_opus_header_is_id_header (buf)) { GST_ERROR_OBJECT (dec, "Header is not an Opus ID header"); return GST_FLOW_ERROR; } gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; if (!(dec->n_channels == 0 || dec->n_channels == data[9])) { gst_buffer_unmap (buf, &map); GST_ERROR_OBJECT (dec, "Opus ID header has invalid channels"); return GST_FLOW_ERROR; } dec->n_channels = data[9]; dec->sample_rate = GST_READ_UINT32_LE (data + 12); dec->pre_skip = GST_READ_UINT16_LE (data + 10); dec->r128_gain = GST_READ_UINT16_LE (data + 16); dec->r128_gain_volume = gst_opus_dec_get_r128_volume (dec->r128_gain); GST_INFO_OBJECT (dec, "Found pre-skip of %u samples, R128 gain %d (volume %f)", dec->pre_skip, dec->r128_gain, dec->r128_gain_volume); dec->channel_mapping_family = data[18]; if (dec->channel_mapping_family == 0) { /* implicit mapping */ GST_INFO_OBJECT (dec, "Channel mapping family 0, implicit mapping"); dec->n_streams = dec->n_stereo_streams = 1; dec->channel_mapping[0] = 0; dec->channel_mapping[1] = 1; } else { dec->n_streams = data[19]; dec->n_stereo_streams = data[20]; memcpy (dec->channel_mapping, data + 21, dec->n_channels); if (dec->channel_mapping_family == 1) { GST_INFO_OBJECT (dec, "Channel mapping family 1, Vorbis mapping"); switch (dec->n_channels) { case 1: case 2: /* nothing */ break; case 3: case 4: case 5: case 6: case 7: case 8: posn = gst_opus_channel_positions[dec->n_channels - 1]; break; default:{ gint i; GST_ELEMENT_WARNING (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("Using NONE channel layout for more than 8 channels")); for (i = 0; i < dec->n_channels; i++) pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE; posn = pos; } } } else { GST_INFO_OBJECT (dec, "Channel mapping family %d", dec->channel_mapping_family); } } gst_opus_dec_negotiate (dec, posn); gst_buffer_unmap (buf, &map); return GST_FLOW_OK; }
static gboolean gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, gint lentype, const guint8 ** p_data, guint * p_size) { AsfPayload payload = { 0, }; AsfStream *stream; gboolean is_compressed; guint payload_len; guint stream_num; if (G_UNLIKELY (*p_size < 1)) { GST_WARNING_OBJECT (demux, "Short packet!"); return FALSE; } stream_num = GST_READ_UINT8 (*p_data) & 0x7f; payload.keyframe = ((GST_READ_UINT8 (*p_data) & 0x80) != 0); *p_data += 1; *p_size -= 1; payload.ts = GST_CLOCK_TIME_NONE; payload.duration = GST_CLOCK_TIME_NONE; payload.par_x = 0; payload.par_y = 0; payload.interlaced = FALSE; payload.tff = FALSE; payload.rff = FALSE; payload.mo_number = asf_packet_read_varlen_int (packet->prop_flags, 4, p_data, p_size); payload.mo_offset = asf_packet_read_varlen_int (packet->prop_flags, 2, p_data, p_size); payload.rep_data_len = asf_packet_read_varlen_int (packet->prop_flags, 0, p_data, p_size); is_compressed = (payload.rep_data_len == 1); GST_LOG_OBJECT (demux, "payload for stream %u", stream_num); GST_LOG_OBJECT (demux, "keyframe : %s", (payload.keyframe) ? "yes" : "no"); GST_LOG_OBJECT (demux, "compressed : %s", (is_compressed) ? "yes" : "no"); if (G_UNLIKELY (*p_size < payload.rep_data_len)) { GST_WARNING_OBJECT (demux, "Short packet! rep_data_len=%u, size=%u", payload.rep_data_len, *p_size); return FALSE; } memcpy (payload.rep_data, *p_data, MIN (sizeof (payload.rep_data), payload.rep_data_len)); *p_data += payload.rep_data_len; *p_size -= payload.rep_data_len; if (G_UNLIKELY (*p_size == 0)) { GST_WARNING_OBJECT (demux, "payload without data!?"); return FALSE; } /* we use -1 as lentype for a single payload that's the size of the packet */ if (G_UNLIKELY ((lentype >= 0 && lentype <= 3))) { payload_len = asf_packet_read_varlen_int (lentype, 0, p_data, p_size); if (*p_size < payload_len) { GST_WARNING_OBJECT (demux, "Short packet! payload_len=%u, size=%u", payload_len, *p_size); return FALSE; } } else { payload_len = *p_size; } GST_LOG_OBJECT (demux, "payload length: %u", payload_len); stream = gst_asf_demux_get_stream (demux, stream_num); if (G_UNLIKELY (stream == NULL)) { GST_WARNING_OBJECT (demux, "Payload for unknown stream %u, skipping", stream_num); if (*p_size < payload_len) { *p_data += *p_size; *p_size = 0; } else { *p_data += payload_len; *p_size -= payload_len; } return TRUE; } if (G_UNLIKELY (!is_compressed)) { GST_LOG_OBJECT (demux, "replicated data length: %u", payload.rep_data_len); if (payload.rep_data_len >= 8) { payload.mo_size = GST_READ_UINT32_LE (payload.rep_data); payload.ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND; if (G_UNLIKELY (payload.ts < demux->preroll)) payload.ts = 0; else payload.ts -= demux->preroll; asf_payload_parse_replicated_data_extensions (stream, &payload); GST_LOG_OBJECT (demux, "media object size : %u", payload.mo_size); GST_LOG_OBJECT (demux, "media object ts : %" GST_TIME_FORMAT, GST_TIME_ARGS (payload.ts)); GST_LOG_OBJECT (demux, "media object dur : %" GST_TIME_FORMAT, GST_TIME_ARGS (payload.duration)); } else if (payload.rep_data_len != 0) { GST_WARNING_OBJECT (demux, "invalid replicated data length, very bad"); *p_data += payload_len; *p_size -= payload_len; return FALSE; } GST_LOG_OBJECT (demux, "media object offset : %u", payload.mo_offset); GST_LOG_OBJECT (demux, "payload length: %u", payload_len); if ((stream = gst_asf_demux_get_stream (demux, stream_num)) && payload_len) { payload.buf = asf_packet_create_payload_buffer (packet, p_data, p_size, payload_len); /* n-th fragment of a fragmented media object? */ if (payload.mo_offset != 0) { AsfPayload *prev; if ((prev = asf_payload_find_previous_fragment (&payload, stream))) { if (payload.mo_offset != GST_BUFFER_SIZE (prev->buf)) { GST_WARNING_OBJECT (demux, "Offset doesn't match previous data?!"); } /* note: buffer join/merge might not preserve buffer flags */ prev->buf = gst_buffer_join (prev->buf, payload.buf); GST_LOG_OBJECT (demux, "Merged fragments, merged size: %u", GST_BUFFER_SIZE (prev->buf)); } else { gst_buffer_unref (payload.buf); } payload.buf = NULL; } else { gst_asf_payload_queue_for_stream (demux, &payload, stream); } } } else { const guint8 *payload_data; GstClockTime ts, ts_delta; guint num; GST_LOG_OBJECT (demux, "Compressed payload, length=%u", payload_len); payload_data = *p_data; *p_data += payload_len; *p_size -= payload_len; ts = payload.mo_offset * GST_MSECOND; if (G_UNLIKELY (ts < demux->preroll)) ts = 0; else ts -= demux->preroll; ts_delta = payload.rep_data[0] * GST_MSECOND; for (num = 0; payload_len > 0; ++num) { guint sub_payload_len; sub_payload_len = GST_READ_UINT8 (payload_data); GST_LOG_OBJECT (demux, "subpayload #%u: len=%u, ts=%" GST_TIME_FORMAT, num, sub_payload_len, GST_TIME_ARGS (ts)); ++payload_data; --payload_len; if (G_UNLIKELY (payload_len < sub_payload_len)) { GST_WARNING_OBJECT (demux, "Short payload! %u bytes left", payload_len); return FALSE; } if (G_LIKELY (sub_payload_len > 0)) { payload.buf = asf_packet_create_payload_buffer (packet, &payload_data, &payload_len, sub_payload_len); payload.ts = ts; if (G_LIKELY (ts_delta)) payload.duration = ts_delta; else payload.duration = GST_CLOCK_TIME_NONE; gst_asf_payload_queue_for_stream (demux, &payload, stream); } ts += ts_delta; } } return TRUE; }