[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid.changes
|
|
[-]
[+]
|
Changed |
_service:tar_git:gst-droid.spec
^
|
|
[-]
[+]
|
Changed |
_service
^
|
@@ -2,6 +2,6 @@
<service name="tar_git">
<param name="url">https://github.com/sailfishos/gst-droid.git</param>
<param name="branch">master</param>
- <param name="revision">d8e3ce347486973f96190c0dee756e00828bcd99</param>
+<!-- <param name="revision">d8e3ce347486973f96190c0dee756e00828bcd99</param> -->
</service>
</services>
|
[-]
[+]
|
Deleted |
_service:tar_git:gstreamer1.0-droid-0.20161124.0.tar.gz/gst/droidcodec/gstdroidcodec.c
^
|
@@ -1,1124 +0,0 @@
-/*
- * gst-droid
- *
- * Copyright (C) 2014-2015 Mohammed Sameer <msameer@foolab.org>
- * Copyright (C) 2015 Jolla LTD.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "gstdroidcodec.h"
-#include "plugin.h"
-#include <glib.h>
-#include <gst/base/gstbytewriter.h>
-#ifndef GST_USE_UNSTABLE_API
-#define GST_USE_UNSTABLE_API
-#endif /* GST_USE_UNSTABLE_API */
-#include <gst/codecparsers/gsth264parser.h>
-
-GST_DEBUG_CATEGORY_EXTERN (gst_droid_codec_debug);
-#define GST_CAT_DEFAULT gst_droid_codec_debug
-
-static GstBuffer *create_mpeg4venc_codec_data (DroidMediaData * data);
-static GstBuffer *create_h264enc_codec_data (DroidMediaData * data);
-static gboolean create_mpeg4vdec_codec_data_from_codec_data (GstDroidCodec *
- codec, GstBuffer * data, DroidMediaData * out);
-static gboolean create_h264dec_codec_data_from_codec_data (GstDroidCodec *
- codec, GstBuffer * data, DroidMediaData * out);
-static gboolean create_vp8vdec_codec_data_from_codec_data (GstDroidCodec *
- codec, GstBuffer * data, DroidMediaData * out);
-static gboolean create_aacdec_codec_data_from_codec_data (GstDroidCodec * codec,
- GstBuffer * data, DroidMediaData * out);
-static gboolean create_aacdec_codec_data_from_frame_data (GstDroidCodec * codec,
- GstBuffer * frame_data, DroidMediaData * out);
-static gboolean process_h264dec_data (GstDroidCodec * codec, GstBuffer * buffer,
- DroidMediaData * out);
-static gboolean process_aacdec_data (GstDroidCodec * codec, GstBuffer * buffer,
- DroidMediaData * out);
-static gboolean is_mpeg4v (GstDroidCodec * codec, const GstStructure * s);
-static gboolean is_mpega (GstDroidCodec * codec, const GstStructure * s);
-static gboolean is_mp3 (GstDroidCodec * codec, const GstStructure * s);
-static gboolean is_h264_dec (GstDroidCodec * codec, const GstStructure * s);
-static gboolean is_h264_enc (GstDroidCodec * codec, const GstStructure * s);
-static void h264enc_complement (GstCaps * caps);
-static gboolean process_h264enc_data (DroidMediaData * in,
- DroidMediaData * out);
-static void gst_droid_codec_release_input_frame (void *data);
-static void gst_droid_codec_free (GstDroidCodec * codec);
-static void gst_droid_codec_type_fill_quirks (GstDroidCodec * codec);
-
-GST_DEFINE_MINI_OBJECT_TYPE (GstDroidCodec, gst_droid_codec);
-
-typedef struct
-{
- gpointer data;
-} GstDroidCodecFrameReleaseData;
-
-struct _GstDroidCodecPrivate
-{
- guint h264_nal;
- gboolean aac_adts;
-};
-
-struct _GstDroidCodecInfo
-{
- GstDroidCodecType type;
- const gchar *mime;
- const gchar *droid;
- const gchar *caps;
- gboolean enabled;
-
- gboolean (*validate_structure) (GstDroidCodec * codec,
- const GstStructure * s);
- void (*complement_caps) (GstCaps * caps);
- GstBuffer *(*create_encoder_codec_data) (DroidMediaData * data);
- gboolean (*process_encoder_data) (DroidMediaData * in,
- DroidMediaData * out);
- gboolean (*create_decoder_codec_data_from_codec_data) (GstDroidCodec *
- codec, GstBuffer * codec_data, DroidMediaData * out);
- gboolean (*create_decoder_codec_data_from_frame_data) (GstDroidCodec *
- codec, GstBuffer * frame_data, DroidMediaData * out);
- gboolean (*process_decoder_data) (GstDroidCodec * codec, GstBuffer * buffer,
- DroidMediaData * out);
-};
-
-/* codecs */
-#define CAPS_FRAGMENT_AUDIO_ENCODER \
- " , channels = (int) [1, 2]"
-
-static GstDroidCodecInfo codecs[] = {
- /* audio decoders */
- {GST_DROID_CODEC_DECODER_AUDIO, "audio/mpeg", "audio/mp4a-latm",
- "audio/mpeg, mpegversion=(int){2, 4}, stream-format=(string){raw, adts}",
- TRUE,
- is_mpega, NULL, NULL, NULL, create_aacdec_codec_data_from_codec_data,
- create_aacdec_codec_data_from_frame_data, process_aacdec_data},
-
- {GST_DROID_CODEC_DECODER_AUDIO, "audio/mpeg", "audio/mpeg",
- "audio/mpeg, mpegversion=(int)1, layer=[1, 3]", TRUE,
- is_mp3, NULL, NULL, NULL, NULL, NULL, NULL},
-
- /* video decoders */
- {GST_DROID_CODEC_DECODER_VIDEO, "video/mpeg", "video/mp4v-es",
- "video/mpeg, mpegversion=4", TRUE,
- is_mpeg4v, NULL, NULL, NULL,
- create_mpeg4vdec_codec_data_from_codec_data, NULL, NULL},
-
- {GST_DROID_CODEC_DECODER_VIDEO, "video/x-h264", "video/avc",
- "video/x-h264, stream-format=avc,alignment=au", TRUE,
- is_h264_dec, NULL, NULL, NULL,
- create_h264dec_codec_data_from_codec_data, NULL, process_h264dec_data},
-
- {GST_DROID_CODEC_DECODER_VIDEO, "video/x-h263", "video/3gpp",
- "video/x-h263", TRUE, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL},
-
- {GST_DROID_CODEC_DECODER_VIDEO, "video/x-vp8", "video/x-vnd.on2.vp8",
- "video/x-vp8", FALSE, NULL, NULL, NULL, NULL,
- create_vp8vdec_codec_data_from_codec_data, NULL, NULL},
-
- /* audio encoders */
- {GST_DROID_CODEC_ENCODER_AUDIO, "audio/mpeg", "audio/mp4a-latm",
- "audio/mpeg, mpegversion=(int)4, stream-format=(string){raw}"
- CAPS_FRAGMENT_AUDIO_ENCODER, TRUE,
- is_mpeg4v, NULL, create_mpeg4venc_codec_data, NULL, NULL, NULL, NULL},
-
- /* video encoders */
- {GST_DROID_CODEC_ENCODER_VIDEO, "video/mpeg", "video/mp4v-es",
- "video/mpeg, mpegversion=4, systemstream=false", TRUE,
- is_mpeg4v, NULL, create_mpeg4venc_codec_data, NULL, NULL, NULL, NULL},
-
- {GST_DROID_CODEC_ENCODER_VIDEO, "video/x-h264", "video/avc",
- "video/x-h264, stream-format=avc,alignment=au", TRUE,
- is_h264_enc, h264enc_complement, create_h264enc_codec_data,
- process_h264enc_data, NULL, NULL, NULL},
-};
-
-GstDroidCodec *
-gst_droid_codec_new_from_caps (GstCaps * caps, GstDroidCodecType type)
-{
- int x = 0;
- int len = G_N_ELEMENTS (codecs);
- GstStructure *s = gst_caps_get_structure (caps, 0);
- const gchar *name = gst_structure_get_name (s);
- GstDroidCodec *codec = g_slice_new (GstDroidCodec);
- codec->data = g_slice_new0 (GstDroidCodecPrivate);
-
- for (x = 0; x < len; x++) {
- if (codecs[x].type != type) {
- continue;
- }
-
- gboolean is_equal = g_strcmp0 (codecs[x].mime, name) == 0;
- if (!is_equal) {
- continue;
- }
-
- if (!codecs[x].validate_structure
- || codecs[x].validate_structure (codec, s)) {
- gst_mini_object_init (GST_MINI_OBJECT_CAST (codec), 0,
- gst_droid_codec_get_type (), NULL, NULL,
- (GstMiniObjectFreeFunction) gst_droid_codec_free);
-
- codec->info = &codecs[x];
-
- /* Fill codec quirks */
- gst_droid_codec_type_fill_quirks (codec);
-
- return codec;
- }
- }
-
- gst_droid_codec_free (codec);
-
- return NULL;
-}
-
-GstCaps *
-gst_droid_codec_get_all_caps (GstDroidCodecType type)
-{
- GstCaps *caps = gst_caps_new_empty ();
- int x = 0;
- int len = G_N_ELEMENTS (codecs);
- GKeyFile *file = g_key_file_new ();
- gchar *path = g_strdup_printf ("%s/gst-droid/gstdroidcodec.conf", SYSCONFDIR);
- gchar *group = type == GST_DROID_CODEC_DECODER_AUDIO
- || type == GST_DROID_CODEC_DECODER_VIDEO ? "decoders" : "encoders";
-
- g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
- g_free (path);
-
- for (x = 0; x < len; x++) {
- gboolean codec_listed;
- gint codec_enabled;
- GstStructure *s;
-
- if (codecs[x].type != type) {
- continue;
- }
-
- /* If the codec is listed in the configuration file then we obey it.
- * Otherwise we fallback to our hard-coded default */
- codec_listed = g_key_file_has_key (file, group, codecs[x].droid, NULL);
- codec_enabled = g_key_file_get_integer (file, group, codecs[x].droid, NULL);
- if ((codec_listed && !codec_enabled) || (!codec_listed
- && !codecs[x].enabled)) {
- GST_INFO ("%s is disabled", codecs[x].droid);
- continue;
- }
-
- s = gst_structure_new_from_string (codecs[x].caps);
- caps = gst_caps_merge_structure (caps, s);
- }
-
- GST_INFO ("caps %" GST_PTR_FORMAT, caps);
-
- g_key_file_free (file);
-
- return caps;
-}
-
-const gchar *
-gst_droid_codec_get_droid_type (GstDroidCodec * codec)
-{
- return codec->info->droid;
-}
-
-void
-gst_droid_codec_free (GstDroidCodec * codec)
-{
- g_slice_free (GstDroidCodecPrivate, codec->data);
- g_slice_free (GstDroidCodec, codec);
-}
-
-void
-gst_droid_codec_complement_caps (GstDroidCodec * codec, GstCaps * caps)
-{
- if (codec->info->complement_caps)
- codec->info->complement_caps (caps);
-}
-
-GstBuffer *
-gst_droid_codec_create_encoder_codec_data (GstDroidCodec * codec,
- DroidMediaData * data)
-{
- return codec->info->create_encoder_codec_data (data);
-}
-
-GstDroidCodecCodecDataResult
-gst_droid_codec_create_decoder_codec_data (GstDroidCodec * codec,
- GstBuffer * data, DroidMediaData * out, GstBuffer * frame_data)
-{
- /* We always have frame_data */
-
- if (data) {
- /* We must process it */
-
- if (!codec->info->create_decoder_codec_data_from_codec_data) {
- return GST_DROID_CODEC_CODEC_DATA_ERROR;
- }
- return codec->info->create_decoder_codec_data_from_codec_data (codec, data,
- out) ? GST_DROID_CODEC_CODEC_DATA_OK : GST_DROID_CODEC_CODEC_DATA_ERROR;
- }
-
- if (!codec->info->create_decoder_codec_data_from_frame_data) {
- return GST_DROID_CODEC_CODEC_DATA_NOT_NEEDED;
- }
-
- return codec->info->create_decoder_codec_data_from_frame_data (codec,
- frame_data,
- out) ? GST_DROID_CODEC_CODEC_DATA_OK : GST_DROID_CODEC_CODEC_DATA_ERROR;
-}
-
-gboolean
-gst_droid_codec_prepare_decoder_frame (GstDroidCodec * codec,
- GstVideoCodecFrame * frame, DroidMediaData * data,
- DroidMediaBufferCallbacks * cb)
-{
- GstDroidCodecFrameReleaseData *release_data;
-
- /*
- * We have multiple cases.
- * H264 nal prefix size 4 -> map the buffer writable, fix up and proceed
- * H264 nal prefix size != 4 -> copy data and fix up.
- * The rest -> map buffer read only and proceed
- * However as I do not believe that the memcpy() is that expensive
- * so we will just copy everything and optimize later if we find issues.
- */
-
- if (codec->info->process_decoder_data) {
- if (!codec->info->process_decoder_data (codec, frame->input_buffer, data)) {
- return FALSE;
- }
- } else {
- data->size = gst_buffer_get_size (frame->input_buffer);
- data->data = g_malloc (data->size);
- gst_buffer_extract (frame->input_buffer, 0, data->data, data->size);
- }
-
- release_data = g_slice_new (GstDroidCodecFrameReleaseData);
-
- release_data->data = data->data;
-
- cb->unref = gst_droid_codec_release_input_frame;
- cb->data = release_data;
-
- return TRUE;
-}
-
-GstBuffer *
-gst_droid_codec_prepare_encoded_data (GstDroidCodec * codec,
- DroidMediaData * in)
-{
- GstBuffer *buffer;
-
- if (codec->info->process_encoder_data) {
- DroidMediaData out;
- if (!codec->info->process_encoder_data (in, &out)) {
- buffer = NULL;
- } else {
- buffer = gst_buffer_new_wrapped (out.data, out.size);
- }
- } else {
- buffer = gst_buffer_new_allocate (NULL, in->size, NULL);
- gst_buffer_fill (buffer, 0, in->data, in->size);
- }
-
- return buffer;
-}
-
-gboolean
-gst_droid_codec_process_decoder_data (GstDroidCodec * codec, GstBuffer * buffer,
- DroidMediaData * out)
-{
- GstMapInfo info;
-
- if (codec->info->process_decoder_data) {
- return codec->info->process_decoder_data (codec, buffer, out);
- }
-
- if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
- return FALSE;
- }
-
- out->size = info.size;
- out->data = g_malloc (info.size);
- memcpy (out->data, info.data, info.size);
- gst_buffer_unmap (buffer, &info);
-
- return TRUE;
-}
-
-gint
-gst_droid_codec_get_samples_per_frane (GstCaps * caps)
-{
- gint mpegversion = -1;
- const GstStructure *s = gst_caps_get_structure (caps, 0);
- const gchar *name = gst_structure_get_name (s);
- if (!g_str_has_prefix (name, "audio/")) {
- return -1;
- }
-
- /* see gst-plugins-bad 5b23cf69 */
- gst_structure_get_int (s, "mpegversion", &mpegversion);
- if (mpegversion == 1) {
- gint layer = -1, mpegaudioversion = -1;
- gst_structure_get_int (s, "layer", &layer);
- gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion);
- if (layer == 1) {
- return 384;
- } else if (layer == 2) {
- return 1152;
- } else if (layer == 3 && mpegaudioversion != -1) {
- return (mpegaudioversion == 1 ? 1152 : 576);
- }
- }
-
- return -1;
-}
-
-static GstBuffer *
-create_mpeg4venc_codec_data (DroidMediaData * data)
-{
- GstBuffer *codec_data = gst_buffer_new_allocate (NULL, data->size, NULL);
-
- gst_buffer_fill (codec_data, 0, data->data, data->size);
-
- GST_BUFFER_OFFSET (codec_data) = 0;
- GST_BUFFER_OFFSET_END (codec_data) = 0;
- GST_BUFFER_PTS (codec_data) = GST_CLOCK_TIME_NONE;
- GST_BUFFER_DTS (codec_data) = GST_CLOCK_TIME_NONE;
- GST_BUFFER_DURATION (codec_data) = GST_CLOCK_TIME_NONE;
- GST_BUFFER_FLAG_SET (codec_data, GST_BUFFER_FLAG_HEADER);
-
- return codec_data;
-}
-
-static GstBuffer *
-create_h264enc_codec_data (DroidMediaData * data)
-{
- GstH264NalParser *parser = gst_h264_nal_parser_new ();
- gsize offset = 0;
- GSList *sps = NULL, *pps = NULL;
- gsize sps_size = 0, pps_size = 0;
- gint num_sps = 0, num_pps = 0;
- GstByteWriter *writer = NULL;
- guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
- gboolean idc_found = FALSE;
- GstBuffer *codec_data = NULL;
- GstH264NalUnit nal;
- GstH264ParserResult res;
- int x;
-
- res =
- gst_h264_parser_identify_nalu (parser, data->data, offset, data->size,
- &nal);
-
- while (res == GST_H264_PARSER_OK || res == GST_H264_PARSER_NO_NAL_END) {
- GstBuffer *buffer = gst_buffer_new_allocate (NULL, nal.size, NULL);
- gst_buffer_fill (buffer, 0, nal.data + nal.offset, nal.size);
-
- offset += (nal.size + nal.offset);
-
- if (nal.type == GST_H264_NAL_SPS) {
- if (nal.size >= 4 && !idc_found) {
- idc_found = TRUE;
-
- profile_idc = nal.data[1];
- profile_comp = nal.data[2];
- level_idc = nal.data[3];
- } else if (nal.size >= 4) {
- if (profile_idc != nal.data[1] || profile_comp != nal.data[2] ||
- level_idc != nal.data[3]) {
- GST_ERROR ("Inconsistency in SPS");
- goto out;
- }
- } else {
- GST_ERROR ("malformed SPS");
- goto out;
- }
-
- GST_MEMDUMP ("Found SPS", nal.data + nal.offset, nal.size);
-
- sps = g_slist_append (sps, buffer);
- sps_size += (nal.size + 2);
- } else if (nal.type == GST_H264_NAL_PPS) {
- GST_MEMDUMP ("Found PPS", nal.data + nal.offset, nal.size);
- pps = g_slist_append (pps, buffer);
- pps_size += (nal.size + 2);
- } else {
- GST_LOG ("NAL is neither SPS nor PPS");
- gst_buffer_unref (buffer);
- }
-
- if (gst_h264_parser_parse_nal (parser, &nal) != GST_H264_PARSER_OK) {
- GST_ERROR ("malformed NAL");
- goto out;
- }
-
- res =
- gst_h264_parser_identify_nalu (parser, data->data, offset, data->size,
- &nal);
- }
-
- if (G_UNLIKELY (!idc_found)) {
- GST_ERROR ("missing codec parameters");
- goto out;
- }
-
- num_sps = g_slist_length (sps);
- if (G_UNLIKELY (num_sps < 1 || num_sps >= GST_H264_MAX_SPS_COUNT)) {
- GST_ERROR ("No SPS found");
- goto out;
- }
-
- num_pps = g_slist_length (pps);
- if (G_UNLIKELY (num_pps < 1 || num_pps >= GST_H264_MAX_PPS_COUNT)) {
- GST_ERROR ("No PPS found");
- goto out;
- }
-
- GST_INFO ("SPS found: %d, PPS found: %d", num_sps, num_pps);
-
- writer = gst_byte_writer_new_with_size (sps_size + pps_size + 7, FALSE);
- gst_byte_writer_put_uint8 (writer, 1); /* AVC decoder configuration version 1 */
- gst_byte_writer_put_uint8 (writer, profile_idc); /* profile idc */
- gst_byte_writer_put_uint8 (writer, profile_comp); /* profile compatibility */
- gst_byte_writer_put_uint8 (writer, level_idc); /* level idc */
- gst_byte_writer_put_uint8 (writer, (0xfc | (4 - 1))); /* nal length size - 1 */
- gst_byte_writer_put_uint8 (writer, 0xe0 | num_sps); /* number of sps */
-
- /* SPS */
- for (x = 0; x < num_sps; x++) {
- GstBuffer *buf = g_slist_nth_data (sps, x);
- GstMapInfo info;
- gst_buffer_map (buf, &info, GST_MAP_READ);
- gst_byte_writer_put_uint8 (writer, info.size >> 8);
- gst_byte_writer_put_uint8 (writer, info.size & 0xff);
- gst_byte_writer_put_data (writer, info.data, info.size);
- gst_buffer_unmap (buf, &info);
- }
-
- gst_byte_writer_put_uint8 (writer, num_pps); /* number of pps */
-
- /* PPS */
- for (x = 0; x < num_pps; x++) {
- GstBuffer *buf = g_slist_nth_data (pps, x);
- GstMapInfo info;
- gst_buffer_map (buf, &info, GST_MAP_READ);
- gst_byte_writer_put_uint8 (writer, info.size >> 8);
- gst_byte_writer_put_uint8 (writer, info.size & 0xff);
- gst_byte_writer_put_data (writer, info.data, info.size);
- gst_buffer_unmap (buf, &info);
- }
-
- codec_data = gst_byte_writer_free_and_get_buffer (writer);
- writer = NULL;
-
-out:
- if (sps) {
- g_slist_free_full (sps, (GDestroyNotify) gst_buffer_unref);
- }
-
- if (pps) {
- g_slist_free_full (pps, (GDestroyNotify) gst_buffer_unref);
- }
-
- if (parser) {
- gst_h264_nal_parser_free (parser);
- }
-
- return codec_data;
-}
-
-static gboolean
-is_mpeg4v (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
-{
- gint val;
-
- return gst_structure_get_int (s, "mpegversion", &val) && val == 4;
-}
-
-static gboolean
-is_mpega (GstDroidCodec * codec, const GstStructure * s)
-{
- const gchar *val;
- gint ver;
-
- if (!gst_structure_get_int (s, "mpegversion", &ver)) {
- return FALSE;
- }
-
- if (!(ver == 2 || ver == 4)) {
- return FALSE;
- }
-
- val = gst_structure_get_string (s, "stream-format");
- if (!val) {
- return FALSE;
- }
-
- if (!g_strcmp0 (val, "raw")) {
- codec->data->aac_adts = FALSE;
- return TRUE;
- } else if (!g_strcmp0 (val, "adts")) {
- codec->data->aac_adts = TRUE;
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-is_mp3 (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
-{
- gint val, layer;
-
- return gst_structure_get_int (s, "mpegversion", &val) && val == 1 &&
- gst_structure_get_int (s, "layer", &layer) && (layer == 1 || layer == 3);
-}
-
-static gboolean
-is_h264_dec (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
-{
- const char *alignment = gst_structure_get_string (s, "alignment");
- const char *format = gst_structure_get_string (s, "stream-format");
-
- /* Enforce alignment and format */
- return alignment && format && !g_strcmp0 (alignment, "au")
- && !g_strcmp0 (format, "avc");
-}
-
-static gboolean
-is_h264_enc (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
-{
- const char *alignment = gst_structure_get_string (s, "alignment");
- const char *format = gst_structure_get_string (s, "stream-format");
-
- /* We can accept caps without alignment or format and will add them later on */
- if (alignment && g_strcmp0 (alignment, "au")) {
- return FALSE;
- }
-
- if (format && g_strcmp0 (format, "avc")) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-h264enc_complement (GstCaps * caps)
-{
- gst_caps_set_simple (caps, "alignment", G_TYPE_STRING, "au",
- "stream-format", G_TYPE_STRING, "avc", NULL);
-}
-
-static gboolean
-create_mpeg4vdec_codec_data_from_codec_data (GstDroidCodec *
- codec G_GNUC_UNUSED, GstBuffer * data, DroidMediaData * out)
-{
- /*
- * If there are things which I hate the most, this function will be among them
- * http://xhelmboyx.tripod.com/formats/mp4-layout.txt
- */
- GstMapInfo info;
- GstByteWriter *writer = NULL;
- codec->data->h264_nal = 0;
-
- if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
- return FALSE;
- }
-
- writer = gst_byte_writer_new_with_size (info.size + 29 - 4, FALSE);
-#if 0 /* stagefright ESDS parser does not like us when we have the first 4 bytes */
- gst_byte_writer_put_uint32_be (writer, 0); /* version and flags */
-#endif
- gst_byte_writer_put_uint8 (writer, 0x03); /* ES descriptor type tag */
- gst_byte_writer_put_uint8 (writer, 23 + info.size); /* size */
- gst_byte_writer_put_uint16_be (writer, 0); /* ES ID */
- gst_byte_writer_put_uint8 (writer, 0x1f); /* priority */
- gst_byte_writer_put_uint8 (writer, 0x04); /* decoder config descriptor type tag */
- gst_byte_writer_put_uint8 (writer, 15 + info.size);
- gst_byte_writer_put_uint8 (writer, 0x20); /* object type: MPEG4 video */
- gst_byte_writer_put_uint8 (writer, 0x11); /* stream type: visual stream */
-
- /* buffer size db, average bit rate and max bit rate values are taken from stagefright MPEG4Writer */
- gst_byte_writer_put_uint8 (writer, 0x01); /* buffer size db: 1/3 */
- gst_byte_writer_put_uint8 (writer, 0x77); /* buffer size db: 2/3 */
- gst_byte_writer_put_uint8 (writer, 0x00); /* buffer size db: 3/3 */
- gst_byte_writer_put_uint8 (writer, 0x00); /* max bit rate: 1/4 */
- gst_byte_writer_put_uint8 (writer, 0x03); /* max bit rate: 2/4 */
- gst_byte_writer_put_uint8 (writer, 0xe8); /* max bit rate: 3/4 */
- gst_byte_writer_put_uint8 (writer, 0x00); /* max bit rate: 4/4 */
-
- gst_byte_writer_put_uint8 (writer, 0x00); /* average bit rate: 1/4 */
- gst_byte_writer_put_uint8 (writer, 0x03); /* average bit rate: 2/4 */
- gst_byte_writer_put_uint8 (writer, 0xe8); /* average bit rate: 3/4 */
- gst_byte_writer_put_uint8 (writer, 0x00); /* average bit rate: 4/4 */
-
- gst_byte_writer_put_uint8 (writer, 0x05); /* decoder specific descriptor type tag */
- gst_byte_writer_put_uint8 (writer, info.size); /* size */
- gst_byte_writer_put_data (writer, info.data, info.size); /* codec data */
-
- gst_byte_writer_put_uint8 (writer, 0x06); /* SL config descriptor type tag */
- gst_byte_writer_put_uint8 (writer, 0x01); /* descriptor type length */
- gst_byte_writer_put_uint8 (writer, 0x02); /* SL value */
-
- out->size = gst_byte_writer_get_size (writer);
- out->data = gst_byte_writer_free_and_get_data (writer);
-
- gst_buffer_unmap (data, &info);
-
- return TRUE;
-}
-
-static gboolean
-create_vp8vdec_codec_data_from_codec_data (GstDroidCodec * codec,
- GstBuffer * data, DroidMediaData * out)
-{
- GstMapInfo info;
- gboolean ret = FALSE;
-
- if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
- return FALSE;
- }
-
- if (info.size < 7 || info.data[0] != 1) {
- GST_ERROR ("malformed codec_data");
- goto out;
- }
-
- out->size = info.size;
- out->data = g_malloc (info.size);
- memcpy (out->data, info.data, info.size);
- ret = TRUE;
-
-out:
- gst_buffer_unmap (data, &info);
-
- return ret;
-}
-
-static gboolean
-create_h264dec_codec_data_from_codec_data (GstDroidCodec * codec,
- GstBuffer * data, DroidMediaData * out)
-{
- GstMapInfo info;
- gboolean ret = FALSE;
-
- if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
- return FALSE;
- }
-
- if (info.size < 7 || info.data[0] != 1) {
- GST_ERROR ("malformed codec_data");
- goto out;
- }
-
- codec->data->h264_nal = (1 + (info.data[4] & 3));
-
- GST_INFO ("nal prefix length %d", codec->data->h264_nal);
-
- out->size = info.size;
- out->data = g_malloc (info.size);
- memcpy (out->data, info.data, info.size);
- ret = TRUE;
-
-out:
- gst_buffer_unmap (data, &info);
-
- return ret;
-}
-
-static int
-write_len (guint8 * buf, int val)
-{
- /* This is some sort of variable-length coding, but the quicktime
- * file(s) I have here all just use a 4-byte version, so we'll do that.
- * Return the number of bytes written;
- */
- buf[0] = ((val >> 21) & 0x7f) | 0x80;
- buf[1] = ((val >> 14) & 0x7f) | 0x80;
- buf[2] = ((val >> 7) & 0x7f) | 0x80;
- buf[3] = ((val >> 0) & 0x7f);
- return 4;
-}
-
-static gboolean
-create_aacdec_codec_data_from_codec_data (GstDroidCodec * codec G_GNUC_UNUSED,
- GstBuffer * data, DroidMediaData * out)
-{
-#define _QT_PUT(__data, __idx, __size, __shift, __num) \
- (((guint8 *) (__data))[__idx] = (((guint##__size) __num) >> __shift) & 0xff)
-#define QT_WRITE_UINT24(data, num) do { \
- _QT_PUT (data, 0, 32, 0, num); \
- _QT_PUT (data, 1, 32, 8, num); \
- _QT_PUT (data, 2, 32, 16, num); \
-} while (0)
-
- GstMapInfo info;
- gboolean ret;
-
- /*
- * blindly based on audiodecoders.c:make_aac_magic_cookie()
- */
-
- if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
-
- ret = FALSE;
- goto out;
- }
-
- int offset = 0;
- int decoder_specific_len = info.size;
- int config_len = 13 + 5 + decoder_specific_len;
- int es_len = 3 + 5 + config_len + 5 + 1;
- int total_len = es_len + 5;
-
- out->size = total_len;
- out->data = g_malloc0 (out->size);
-
- /* Structured something like this:
- * [ES Descriptor
- * [Config Descriptor
- * [Specific Descriptor]]
- * [Unknown]]
- */
-
- GST_WRITE_UINT8 (out->data + offset, 0x03);
- offset += 1; /* ES Descriptor tag */
- offset += write_len (out->data + offset, es_len);
- GST_WRITE_UINT16_LE (out->data + offset, 0);
- offset += 2; /* Track ID */
- GST_WRITE_UINT8 (out->data + offset, 0);
- offset += 1; /* Flags */
-
- GST_WRITE_UINT8 (out->data + offset, 0x04);
- offset += 1; /* Config Descriptor tag */
- offset += write_len (out->data + offset, config_len);
-
- /* TODO: Fix these up */
- GST_WRITE_UINT8 (out->data + offset, 0x40);
- offset += 1; /* object_type_id */
- GST_WRITE_UINT8 (out->data + offset, 0x15);
- offset += 1; /* stream_type */
- QT_WRITE_UINT24 (out->data + offset, 0x1800);
- offset += 3; /* buffer_size_db */
- GST_WRITE_UINT32_LE (out->data + offset, 128000);
- offset += 4; /* max_bitrate */
- GST_WRITE_UINT32_LE (out->data + offset, 128000);
- offset += 4; /* avg_bitrate */
-
- GST_WRITE_UINT8 (out->data + offset, 0x05);
- offset += 1; /* Specific Descriptor tag */
- offset += write_len (out->data + offset, decoder_specific_len);
- memcpy (out->data + offset, info.data, decoder_specific_len);
- offset += decoder_specific_len;
-
- /* TODO: What is this? 'SL descriptor' apparently, but what does that mean? */
- GST_WRITE_UINT8 (out->data + offset, 0x06);
- offset += 1; /* SL Descriptor tag */
- offset += write_len (out->data + offset, 1);
- GST_WRITE_UINT8 (out->data + offset, 2);
- offset += 1;
-
- gst_buffer_unmap (data, &info);
-
- ret = TRUE;
-
-out:
- return ret;
-}
-
-static gboolean
-create_aacdec_codec_data_from_frame_data (GstDroidCodec * codec,
- GstBuffer * frame_data, DroidMediaData * out)
-{
- GstMapInfo info;
- gboolean ret;
- GstBuffer *data;
-
- guint8 codec_data[2];
- guint16 codec_data_data;
- gint sr_idx;
- gint object;
- gint channels;
-
- if (!codec->data->aac_adts) {
- GST_ERROR ("not ADTS stream");
- return FALSE;
- }
-
- /* stolen from gstaacparse.c */
-
- GST_INFO ("constructing ADTS codec_data");
-
- // TODO: size, TODO: error
- if (!gst_buffer_map (frame_data, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
- return FALSE;
- }
-
- sr_idx = (info.data[2] & 0x3c) >> 2;
- object = ((info.data[2] & 0xc0) >> 6) + 1;
- channels = ((info.data[2] & 0x01) << 2) | ((info.data[3] & 0xc0) >> 6);
- GST_INFO ("AAC info: sample rate index: %d, object type: %d, channels: %d",
- sr_idx, object, channels);
- gst_buffer_unmap (frame_data, &info);
-
- codec_data_data = (object << 11) | sr_idx << 7 | channels << 3;
-
- GST_WRITE_UINT16_BE (codec_data, codec_data_data);
-
- data = gst_buffer_new_and_alloc (2);
- gst_buffer_fill (data, 0, codec_data, 2);
-
- ret = create_aacdec_codec_data_from_codec_data (codec, data, out);
-
- gst_buffer_unref (data);
-
- return ret;
-}
-
-static gboolean
-process_h264dec_data (GstDroidCodec * codec, GstBuffer * buffer,
- DroidMediaData * out)
-{
- GstMapInfo info;
- gboolean ret = FALSE;
- GstByteReader reader;
- GstByteWriter *writer = NULL;
-
- if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
- return FALSE;
- }
-
- if (info.size < codec->data->h264_nal) {
- GST_ERROR ("malformed data");
- goto out;
- }
-
- /* initial validation */
- switch (codec->data->h264_nal) {
- case 4:
- case 2:
- case 3:
- case 1:
- break;
-
- default:
- GST_ERROR ("unhandled nal prefix size %d", codec->data->h264_nal);
- goto out;
- }
-
- gst_byte_reader_init (&reader, info.data, info.size);
-
- /* info.size is our best estimate and should be correct if nal prefix is 4 bytes which is most of the cases */
- writer = gst_byte_writer_new_with_size (info.size, FALSE);
-
- while (gst_byte_reader_get_pos (&reader) < info.size) {
- guint len = 0;
- guint16 len16 = 0;
- guint8 len8 = 0;
- gboolean success = FALSE;
- const guint8 *data = NULL;
-
- switch (codec->data->h264_nal) {
- case 4:
- success = gst_byte_reader_get_uint32_be (&reader, &len);
- break;
-
- case 3:
- success = gst_byte_reader_get_uint24_be (&reader, &len);
- break;
-
- case 2:
- success = gst_byte_reader_get_uint16_be (&reader, &len16);
- len = len16;
- break;
-
- case 1:
- success = gst_byte_reader_get_uint8 (&reader, &len8);
- len = len8;
- break;
-
- default:
- g_assert_not_reached ();
- break;
- }
-
- if (!success) {
- GST_ERROR ("malformed NAL");
- goto out;
- }
-
- if (!gst_byte_writer_put_data (writer, (guint8 *) "\x00\x00\x00\x01", 4)) {
- GST_ERROR ("failed to write NAL prefix");
- goto out;
- }
-
- if (!gst_byte_reader_get_data (&reader, len, &data)) {
- GST_ERROR ("failed to read NAL");
- goto out;
- }
-
- if (!gst_byte_writer_put_data (writer, data, len)) {
- GST_ERROR ("failed to write NAL");
- goto out;
- }
-
- GST_LOG ("parsed nal unit of size %d", len);
- }
-
- out->size = gst_byte_writer_get_size (writer);
- out->data = gst_byte_writer_free_and_get_data (writer);
- writer = NULL;
- ret = TRUE;
-
-out:
- if (writer) {
- gst_byte_writer_free (writer);
- writer = NULL;
- }
-
- gst_buffer_unmap (buffer, &info);
-
- return ret;
-}
-
-static gboolean
-process_aacdec_data (GstDroidCodec * codec, GstBuffer * buffer,
- DroidMediaData * out)
-{
- GstMapInfo info;
-
- if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
- GST_ERROR ("failed to map buffer");
- return FALSE;
- }
-
- if (!codec->data->aac_adts) {
- out->size = info.size;
- out->data = g_malloc (info.size);
- memcpy (out->data, info.data, info.size);
- } else {
- /* stolen from gstaacparse.c */
- guint header_size = (info.data[1] & 1) ? 7 : 9; /* optional CRC */
- out->size = info.size - header_size;
- out->data = g_malloc (out->size);
- memcpy (out->data, info.data + header_size, out->size);
- GST_LOG ("stripping %d bytes", header_size);
- }
-
- gst_buffer_unmap (buffer, &info);
-
- return TRUE;
-}
-
-static gboolean
-process_h264enc_data (DroidMediaData * in, DroidMediaData * out)
-{
- guint32 size;
- guint8 *data;
-
- if (in->size >= 4 && memcmp (in->data, "\x00\x00\x00\x01", 4) == 0) {
- /* We will replace the first 4 bytes with the NAL size */
- out->size = in->size;
- data = in->data + 4;
- } else {
- /* We don't have the NAL prefix so we add 4 bytes for the NAL size */
- out->size = in->size + 4;
- data = in->data;
- }
-
- size = GUINT32_TO_BE (out->size - 4);
- out->data = g_malloc (out->size);
- if (!out->data) {
- return FALSE;
- }
-
- memcpy (out->data, &size, sizeof (size));
- memcpy (out->data + 4, data, out->size - 4);
-
- return TRUE;
-}
-
-static void
-gst_droid_codec_release_input_frame (void *data)
-{
- GstDroidCodecFrameReleaseData *info = (GstDroidCodecFrameReleaseData *) data;
-
- g_free (info->data);
-
- g_slice_free (GstDroidCodecFrameReleaseData, info);
-}
-
-static void
-gst_droid_codec_type_fill_quirks (GstDroidCodec * codec)
-{
- GKeyFile *file = g_key_file_new ();
- gchar *path = g_strdup_printf ("%s/gst-droid/gstdroidcodec.conf", SYSCONFDIR);
- gchar **quirks_string = NULL;
- const gchar *group
- = (codec->info->type == GST_DROID_CODEC_DECODER_AUDIO
- || codec->info->type ==
- GST_DROID_CODEC_DECODER_VIDEO) ? "decoder-quirks" : "encoder-quirks";
- gsize quirks_length = 0;
- int x;
-
- g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
- g_free (path);
-
- if (!g_key_file_has_group (file, group)) {
- GST_LOG ("no quirks");
- goto out;
- }
-
- quirks_string =
- g_key_file_get_string_list (file, group, codec->info->droid,
- &quirks_length, NULL);
- if (!quirks_string) {
- GST_LOG ("no quirks for %s", codec->info->droid);
- goto out;
- }
-
- for (x = 0; x < quirks_length; x++) {
- if (!g_strcmp0 (quirks_string[x], USE_CODEC_SUPPLIED_HEIGHT_NAME)) {
- codec->quirks |= USE_CODEC_SUPPLIED_HEIGHT_VALUE;
- } else if (!g_strcmp0 (quirks_string[x], USE_CODEC_SUPPLIED_WIDTH_NAME)) {
- codec->quirks |= USE_CODEC_SUPPLIED_WIDTH_VALUE;
- }
- }
-
-out:
- g_key_file_free (file);
- file = NULL;
-
- if (quirks_string) {
- g_strfreev (quirks_string);
- quirks_string = NULL;
- }
-}
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst-libs/gst/droid/Makefile.am
^
|
@@ -1,3 +1,4 @@
+AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\"
lib_LTLIBRARIES = libgstdroid-@GST_API_VERSION@.la
libgstdroid_@GST_API_VERSION@_ladir = $(libdir)
@@ -15,10 +16,12 @@
gstdroidmediabuffer.c \
gstdroidbufferpool.c \
gstdroidquery.c \
+ gstdroidcodec.c \
/usr/share/droidmedia/hybris.c
libgstdroid_@GST_API_VERSION@_la_include_HEADERS = \
gstwrappedmemory.h \
gstdroidmediabuffer.h \
gstdroidbufferpool.h \
- gstdroidquery.h
+ gstdroidquery.h \
+ gstdroidcodec.h
\ No newline at end of file
|
[-]
[+]
|
Added |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst-libs/gst/droid/gstdroidcodec.c
^
|
@@ -0,0 +1,1123 @@
+/*
+ * gst-droid
+ *
+ * Copyright (C) 2014-2015 Mohammed Sameer <msameer@foolab.org>
+ * Copyright (C) 2015 Jolla LTD.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstdroidcodec.h"
+#include <glib.h>
+#include <gst/base/gstbytewriter.h>
+#ifndef GST_USE_UNSTABLE_API
+#define GST_USE_UNSTABLE_API
+#endif /* GST_USE_UNSTABLE_API */
+#include <gst/codecparsers/gsth264parser.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_droid_codec_debug);
+#define GST_CAT_DEFAULT gst_droid_codec_debug
+
+static GstBuffer *create_mpeg4venc_codec_data (DroidMediaData * data);
+static GstBuffer *create_h264enc_codec_data (DroidMediaData * data);
+static gboolean create_mpeg4vdec_codec_data_from_codec_data (GstDroidCodec *
+ codec, GstBuffer * data, DroidMediaData * out);
+static gboolean create_h264dec_codec_data_from_codec_data (GstDroidCodec *
+ codec, GstBuffer * data, DroidMediaData * out);
+static gboolean create_vp8vdec_codec_data_from_codec_data (GstDroidCodec *
+ codec, GstBuffer * data, DroidMediaData * out);
+static gboolean create_aacdec_codec_data_from_codec_data (GstDroidCodec * codec,
+ GstBuffer * data, DroidMediaData * out);
+static gboolean create_aacdec_codec_data_from_frame_data (GstDroidCodec * codec,
+ GstBuffer * frame_data, DroidMediaData * out);
+static gboolean process_h264dec_data (GstDroidCodec * codec, GstBuffer * buffer,
+ DroidMediaData * out);
+static gboolean process_aacdec_data (GstDroidCodec * codec, GstBuffer * buffer,
+ DroidMediaData * out);
+static gboolean is_mpeg4v (GstDroidCodec * codec, const GstStructure * s);
+static gboolean is_mpega (GstDroidCodec * codec, const GstStructure * s);
+static gboolean is_mp3 (GstDroidCodec * codec, const GstStructure * s);
+static gboolean is_h264_dec (GstDroidCodec * codec, const GstStructure * s);
+static gboolean is_h264_enc (GstDroidCodec * codec, const GstStructure * s);
+static void h264enc_complement (GstCaps * caps);
+static gboolean process_h264enc_data (DroidMediaData * in,
+ DroidMediaData * out);
+static void gst_droid_codec_release_input_frame (void *data);
+static void gst_droid_codec_free (GstDroidCodec * codec);
+static void gst_droid_codec_type_fill_quirks (GstDroidCodec * codec);
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstDroidCodec, gst_droid_codec);
+
+typedef struct
+{
+ gpointer data;
+} GstDroidCodecFrameReleaseData;
+
+struct _GstDroidCodecPrivate
+{
+ guint h264_nal;
+ gboolean aac_adts;
+};
+
+struct _GstDroidCodecInfo
+{
+ GstDroidCodecType type;
+ const gchar *mime;
+ const gchar *droid;
+ const gchar *caps;
+ gboolean enabled;
+
+ gboolean (*validate_structure) (GstDroidCodec * codec,
+ const GstStructure * s);
+ void (*complement_caps) (GstCaps * caps);
+ GstBuffer *(*create_encoder_codec_data) (DroidMediaData * data);
+ gboolean (*process_encoder_data) (DroidMediaData * in,
+ DroidMediaData * out);
+ gboolean (*create_decoder_codec_data_from_codec_data) (GstDroidCodec *
+ codec, GstBuffer * codec_data, DroidMediaData * out);
+ gboolean (*create_decoder_codec_data_from_frame_data) (GstDroidCodec *
+ codec, GstBuffer * frame_data, DroidMediaData * out);
+ gboolean (*process_decoder_data) (GstDroidCodec * codec, GstBuffer * buffer,
+ DroidMediaData * out);
+};
+
+/* codecs */
+#define CAPS_FRAGMENT_AUDIO_ENCODER \
+ " , channels = (int) [1, 2]"
+
+static GstDroidCodecInfo codecs[] = {
+ /* audio decoders */
+ {GST_DROID_CODEC_DECODER_AUDIO, "audio/mpeg", "audio/mp4a-latm",
+ "audio/mpeg, mpegversion=(int){2, 4}, stream-format=(string){raw, adts}",
+ TRUE,
+ is_mpega, NULL, NULL, NULL, create_aacdec_codec_data_from_codec_data,
+ create_aacdec_codec_data_from_frame_data, process_aacdec_data},
+
+ {GST_DROID_CODEC_DECODER_AUDIO, "audio/mpeg", "audio/mpeg",
+ "audio/mpeg, mpegversion=(int)1, layer=[1, 3]", TRUE,
+ is_mp3, NULL, NULL, NULL, NULL, NULL, NULL},
+
+ /* video decoders */
+ {GST_DROID_CODEC_DECODER_VIDEO, "video/mpeg", "video/mp4v-es",
+ "video/mpeg, mpegversion=4", TRUE,
+ is_mpeg4v, NULL, NULL, NULL,
+ create_mpeg4vdec_codec_data_from_codec_data, NULL, NULL},
+
+ {GST_DROID_CODEC_DECODER_VIDEO, "video/x-h264", "video/avc",
+ "video/x-h264, stream-format=avc,alignment=au", TRUE,
+ is_h264_dec, NULL, NULL, NULL,
+ create_h264dec_codec_data_from_codec_data, NULL, process_h264dec_data},
+
+ {GST_DROID_CODEC_DECODER_VIDEO, "video/x-h263", "video/3gpp",
+ "video/x-h263", TRUE, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL},
+
+ {GST_DROID_CODEC_DECODER_VIDEO, "video/x-vp8", "video/x-vnd.on2.vp8",
+ "video/x-vp8", TRUE, NULL, NULL, NULL, NULL,
+ create_vp8vdec_codec_data_from_codec_data, NULL, NULL},
+
+ /* audio encoders */
+ {GST_DROID_CODEC_ENCODER_AUDIO, "audio/mpeg", "audio/mp4a-latm",
+ "audio/mpeg, mpegversion=(int)4, stream-format=(string){raw}"
+ CAPS_FRAGMENT_AUDIO_ENCODER, TRUE,
+ is_mpeg4v, NULL, create_mpeg4venc_codec_data, NULL, NULL, NULL, NULL},
+
+ /* video encoders */
+ {GST_DROID_CODEC_ENCODER_VIDEO, "video/mpeg", "video/mp4v-es",
+ "video/mpeg, mpegversion=4, systemstream=false", TRUE,
+ is_mpeg4v, NULL, create_mpeg4venc_codec_data, NULL, NULL, NULL, NULL},
+
+ {GST_DROID_CODEC_ENCODER_VIDEO, "video/x-h264", "video/avc",
+ "video/x-h264, stream-format=avc,alignment=au", TRUE,
+ is_h264_enc, h264enc_complement, create_h264enc_codec_data,
+ process_h264enc_data, NULL, NULL, NULL},
+};
+
+GstDroidCodec *
+gst_droid_codec_new_from_caps (GstCaps * caps, GstDroidCodecType type)
+{
+ int x = 0;
+ int len = G_N_ELEMENTS (codecs);
+ GstStructure *s = gst_caps_get_structure (caps, 0);
+ const gchar *name = gst_structure_get_name (s);
+ GstDroidCodec *codec = g_slice_new (GstDroidCodec);
+ codec->data = g_slice_new0 (GstDroidCodecPrivate);
+
+ for (x = 0; x < len; x++) {
+ if (codecs[x].type != type) {
+ continue;
+ }
+
+ gboolean is_equal = g_strcmp0 (codecs[x].mime, name) == 0;
+ if (!is_equal) {
+ continue;
+ }
+
+ if (!codecs[x].validate_structure
+ || codecs[x].validate_structure (codec, s)) {
+ gst_mini_object_init (GST_MINI_OBJECT_CAST (codec), 0,
+ gst_droid_codec_get_type (), NULL, NULL,
+ (GstMiniObjectFreeFunction) gst_droid_codec_free);
+
+ codec->info = &codecs[x];
+
+ /* Fill codec quirks */
+ gst_droid_codec_type_fill_quirks (codec);
+
+ return codec;
+ }
+ }
+
+ gst_droid_codec_free (codec);
+
+ return NULL;
+}
+
+GstCaps *
+gst_droid_codec_get_all_caps (GstDroidCodecType type)
+{
+ GstCaps *caps = gst_caps_new_empty ();
+ int x = 0;
+ int len = G_N_ELEMENTS (codecs);
+ GKeyFile *file = g_key_file_new ();
+ gchar *path = g_strdup_printf ("%s/gst-droid/gstdroidcodec.conf", SYSCONFDIR);
+ gchar *group = type == GST_DROID_CODEC_DECODER_AUDIO
+ || type == GST_DROID_CODEC_DECODER_VIDEO ? "decoders" : "encoders";
+
+ g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
+ g_free (path);
+
+ for (x = 0; x < len; x++) {
+ gboolean codec_listed;
+ gint codec_enabled;
+ GstStructure *s;
+
+ if (codecs[x].type != type) {
+ continue;
+ }
+
+ /* If the codec is listed in the configuration file then we obey it.
+ * Otherwise we fallback to our hard-coded default */
+ codec_listed = g_key_file_has_key (file, group, codecs[x].droid, NULL);
+ codec_enabled = g_key_file_get_integer (file, group, codecs[x].droid, NULL);
+ if ((codec_listed && !codec_enabled) || (!codec_listed
+ && !codecs[x].enabled)) {
+ GST_INFO ("%s is disabled", codecs[x].droid);
+ continue;
+ }
+
+ s = gst_structure_new_from_string (codecs[x].caps);
+ caps = gst_caps_merge_structure (caps, s);
+ }
+
+ GST_INFO ("caps %" GST_PTR_FORMAT, caps);
+
+ g_key_file_free (file);
+
+ return caps;
+}
+
+const gchar *
+gst_droid_codec_get_droid_type (GstDroidCodec * codec)
+{
+ return codec->info->droid;
+}
+
+void
+gst_droid_codec_free (GstDroidCodec * codec)
+{
+ g_slice_free (GstDroidCodecPrivate, codec->data);
+ g_slice_free (GstDroidCodec, codec);
+}
+
+void
+gst_droid_codec_complement_caps (GstDroidCodec * codec, GstCaps * caps)
+{
+ if (codec->info->complement_caps)
+ codec->info->complement_caps (caps);
+}
+
+GstBuffer *
+gst_droid_codec_create_encoder_codec_data (GstDroidCodec * codec,
+ DroidMediaData * data)
+{
+ return codec->info->create_encoder_codec_data (data);
+}
+
+GstDroidCodecCodecDataResult
+gst_droid_codec_create_decoder_codec_data (GstDroidCodec * codec,
+ GstBuffer * data, DroidMediaData * out, GstBuffer * frame_data)
+{
+ /* We always have frame_data */
+
+ if (data) {
+ /* We must process it */
+
+ if (!codec->info->create_decoder_codec_data_from_codec_data) {
+ return GST_DROID_CODEC_CODEC_DATA_ERROR;
+ }
+ return codec->info->create_decoder_codec_data_from_codec_data (codec, data,
+ out) ? GST_DROID_CODEC_CODEC_DATA_OK : GST_DROID_CODEC_CODEC_DATA_ERROR;
+ }
+
+ if (!codec->info->create_decoder_codec_data_from_frame_data) {
+ return GST_DROID_CODEC_CODEC_DATA_NOT_NEEDED;
+ }
+
+ return codec->info->create_decoder_codec_data_from_frame_data (codec,
+ frame_data,
+ out) ? GST_DROID_CODEC_CODEC_DATA_OK : GST_DROID_CODEC_CODEC_DATA_ERROR;
+}
+
+gboolean
+gst_droid_codec_prepare_decoder_frame (GstDroidCodec * codec,
+ GstVideoCodecFrame * frame, DroidMediaData * data,
+ DroidMediaBufferCallbacks * cb)
+{
+ GstDroidCodecFrameReleaseData *release_data;
+
+ /*
+ * We have multiple cases.
+ * H264 nal prefix size 4 -> map the buffer writable, fix up and proceed
+ * H264 nal prefix size != 4 -> copy data and fix up.
+ * The rest -> map buffer read only and proceed
+ * However as I do not believe that the memcpy() is that expensive
+ * so we will just copy everything and optimize later if we find issues.
+ */
+
+ if (codec->info->process_decoder_data) {
+ if (!codec->info->process_decoder_data (codec, frame->input_buffer, data)) {
+ return FALSE;
+ }
+ } else {
+ data->size = gst_buffer_get_size (frame->input_buffer);
+ data->data = g_malloc (data->size);
+ gst_buffer_extract (frame->input_buffer, 0, data->data, data->size);
+ }
+
+ release_data = g_slice_new (GstDroidCodecFrameReleaseData);
+
+ release_data->data = data->data;
+
+ cb->unref = gst_droid_codec_release_input_frame;
+ cb->data = release_data;
+
+ return TRUE;
+}
+
+GstBuffer *
+gst_droid_codec_prepare_encoded_data (GstDroidCodec * codec,
+ DroidMediaData * in)
+{
+ GstBuffer *buffer;
+
+ if (codec->info->process_encoder_data) {
+ DroidMediaData out;
+ if (!codec->info->process_encoder_data (in, &out)) {
+ buffer = NULL;
+ } else {
+ buffer = gst_buffer_new_wrapped (out.data, out.size);
+ }
+ } else {
+ buffer = gst_buffer_new_allocate (NULL, in->size, NULL);
+ gst_buffer_fill (buffer, 0, in->data, in->size);
+ }
+
+ return buffer;
+}
+
+gboolean
+gst_droid_codec_process_decoder_data (GstDroidCodec * codec, GstBuffer * buffer,
+ DroidMediaData * out)
+{
+ GstMapInfo info;
+
+ if (codec->info->process_decoder_data) {
+ return codec->info->process_decoder_data (codec, buffer, out);
+ }
+
+ if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+ return FALSE;
+ }
+
+ out->size = info.size;
+ out->data = g_malloc (info.size);
+ memcpy (out->data, info.data, info.size);
+ gst_buffer_unmap (buffer, &info);
+
+ return TRUE;
+}
+
+gint
+gst_droid_codec_get_samples_per_frane (GstCaps * caps)
+{
+ gint mpegversion = -1;
+ const GstStructure *s = gst_caps_get_structure (caps, 0);
+ const gchar *name = gst_structure_get_name (s);
+ if (!g_str_has_prefix (name, "audio/")) {
+ return -1;
+ }
+
+ /* see gst-plugins-bad 5b23cf69 */
+ gst_structure_get_int (s, "mpegversion", &mpegversion);
+ if (mpegversion == 1) {
+ gint layer = -1, mpegaudioversion = -1;
+ gst_structure_get_int (s, "layer", &layer);
+ gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion);
+ if (layer == 1) {
+ return 384;
+ } else if (layer == 2) {
+ return 1152;
+ } else if (layer == 3 && mpegaudioversion != -1) {
+ return (mpegaudioversion == 1 ? 1152 : 576);
+ }
+ }
+
+ return -1;
+}
+
+static GstBuffer *
+create_mpeg4venc_codec_data (DroidMediaData * data)
+{
+ GstBuffer *codec_data = gst_buffer_new_allocate (NULL, data->size, NULL);
+
+ gst_buffer_fill (codec_data, 0, data->data, data->size);
+
+ GST_BUFFER_OFFSET (codec_data) = 0;
+ GST_BUFFER_OFFSET_END (codec_data) = 0;
+ GST_BUFFER_PTS (codec_data) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DTS (codec_data) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DURATION (codec_data) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_FLAG_SET (codec_data, GST_BUFFER_FLAG_HEADER);
+
+ return codec_data;
+}
+
+static GstBuffer *
+create_h264enc_codec_data (DroidMediaData * data)
+{
+ GstH264NalParser *parser = gst_h264_nal_parser_new ();
+ gsize offset = 0;
+ GSList *sps = NULL, *pps = NULL;
+ gsize sps_size = 0, pps_size = 0;
+ gint num_sps = 0, num_pps = 0;
+ GstByteWriter *writer = NULL;
+ guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
+ gboolean idc_found = FALSE;
+ GstBuffer *codec_data = NULL;
+ GstH264NalUnit nal;
+ GstH264ParserResult res;
+ int x;
+
+ res =
+ gst_h264_parser_identify_nalu (parser, data->data, offset, data->size,
+ &nal);
+
+ while (res == GST_H264_PARSER_OK || res == GST_H264_PARSER_NO_NAL_END) {
+ GstBuffer *buffer = gst_buffer_new_allocate (NULL, nal.size, NULL);
+ gst_buffer_fill (buffer, 0, nal.data + nal.offset, nal.size);
+
+ offset += (nal.size + nal.offset);
+
+ if (nal.type == GST_H264_NAL_SPS) {
+ if (nal.size >= 4 && !idc_found) {
+ idc_found = TRUE;
+
+ profile_idc = nal.data[1];
+ profile_comp = nal.data[2];
+ level_idc = nal.data[3];
+ } else if (nal.size >= 4) {
+ if (profile_idc != nal.data[1] || profile_comp != nal.data[2] ||
+ level_idc != nal.data[3]) {
+ GST_ERROR ("Inconsistency in SPS");
+ goto out;
+ }
+ } else {
+ GST_ERROR ("malformed SPS");
+ goto out;
+ }
+
+ GST_MEMDUMP ("Found SPS", nal.data + nal.offset, nal.size);
+
+ sps = g_slist_append (sps, buffer);
+ sps_size += (nal.size + 2);
+ } else if (nal.type == GST_H264_NAL_PPS) {
+ GST_MEMDUMP ("Found PPS", nal.data + nal.offset, nal.size);
+ pps = g_slist_append (pps, buffer);
+ pps_size += (nal.size + 2);
+ } else {
+ GST_LOG ("NAL is neither SPS nor PPS");
+ gst_buffer_unref (buffer);
+ }
+
+ if (gst_h264_parser_parse_nal (parser, &nal) != GST_H264_PARSER_OK) {
+ GST_ERROR ("malformed NAL");
+ goto out;
+ }
+
+ res =
+ gst_h264_parser_identify_nalu (parser, data->data, offset, data->size,
+ &nal);
+ }
+
+ if (G_UNLIKELY (!idc_found)) {
+ GST_ERROR ("missing codec parameters");
+ goto out;
+ }
+
+ num_sps = g_slist_length (sps);
+ if (G_UNLIKELY (num_sps < 1 || num_sps >= GST_H264_MAX_SPS_COUNT)) {
+ GST_ERROR ("No SPS found");
+ goto out;
+ }
+
+ num_pps = g_slist_length (pps);
+ if (G_UNLIKELY (num_pps < 1 || num_pps >= GST_H264_MAX_PPS_COUNT)) {
+ GST_ERROR ("No PPS found");
+ goto out;
+ }
+
+ GST_INFO ("SPS found: %d, PPS found: %d", num_sps, num_pps);
+
+ writer = gst_byte_writer_new_with_size (sps_size + pps_size + 7, FALSE);
+ gst_byte_writer_put_uint8 (writer, 1); /* AVC decoder configuration version 1 */
+ gst_byte_writer_put_uint8 (writer, profile_idc); /* profile idc */
+ gst_byte_writer_put_uint8 (writer, profile_comp); /* profile compatibility */
+ gst_byte_writer_put_uint8 (writer, level_idc); /* level idc */
+ gst_byte_writer_put_uint8 (writer, (0xfc | (4 - 1))); /* nal length size - 1 */
+ gst_byte_writer_put_uint8 (writer, 0xe0 | num_sps); /* number of sps */
+
+ /* SPS */
+ for (x = 0; x < num_sps; x++) {
+ GstBuffer *buf = g_slist_nth_data (sps, x);
+ GstMapInfo info;
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ gst_byte_writer_put_uint8 (writer, info.size >> 8);
+ gst_byte_writer_put_uint8 (writer, info.size & 0xff);
+ gst_byte_writer_put_data (writer, info.data, info.size);
+ gst_buffer_unmap (buf, &info);
+ }
+
+ gst_byte_writer_put_uint8 (writer, num_pps); /* number of pps */
+
+ /* PPS */
+ for (x = 0; x < num_pps; x++) {
+ GstBuffer *buf = g_slist_nth_data (pps, x);
+ GstMapInfo info;
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ gst_byte_writer_put_uint8 (writer, info.size >> 8);
+ gst_byte_writer_put_uint8 (writer, info.size & 0xff);
+ gst_byte_writer_put_data (writer, info.data, info.size);
+ gst_buffer_unmap (buf, &info);
+ }
+
+ codec_data = gst_byte_writer_free_and_get_buffer (writer);
+ writer = NULL;
+
+out:
+ if (sps) {
+ g_slist_free_full (sps, (GDestroyNotify) gst_buffer_unref);
+ }
+
+ if (pps) {
+ g_slist_free_full (pps, (GDestroyNotify) gst_buffer_unref);
+ }
+
+ if (parser) {
+ gst_h264_nal_parser_free (parser);
+ }
+
+ return codec_data;
+}
+
+static gboolean
+is_mpeg4v (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
+{
+ gint val;
+
+ return gst_structure_get_int (s, "mpegversion", &val) && val == 4;
+}
+
+static gboolean
+is_mpega (GstDroidCodec * codec, const GstStructure * s)
+{
+ const gchar *val;
+ gint ver;
+
+ if (!gst_structure_get_int (s, "mpegversion", &ver)) {
+ return FALSE;
+ }
+
+ if (!(ver == 2 || ver == 4)) {
+ return FALSE;
+ }
+
+ val = gst_structure_get_string (s, "stream-format");
+ if (!val) {
+ return FALSE;
+ }
+
+ if (!g_strcmp0 (val, "raw")) {
+ codec->data->aac_adts = FALSE;
+ return TRUE;
+ } else if (!g_strcmp0 (val, "adts")) {
+ codec->data->aac_adts = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+is_mp3 (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
+{
+ gint val, layer;
+
+ return gst_structure_get_int (s, "mpegversion", &val) && val == 1 &&
+ gst_structure_get_int (s, "layer", &layer) && (layer == 1 || layer == 3);
+}
+
+static gboolean
+is_h264_dec (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
+{
+ const char *alignment = gst_structure_get_string (s, "alignment");
+ const char *format = gst_structure_get_string (s, "stream-format");
+
+ /* Enforce alignment and format */
+ return alignment && format && !g_strcmp0 (alignment, "au")
+ && !g_strcmp0 (format, "avc");
+}
+
+static gboolean
+is_h264_enc (GstDroidCodec * codec G_GNUC_UNUSED, const GstStructure * s)
+{
+ const char *alignment = gst_structure_get_string (s, "alignment");
+ const char *format = gst_structure_get_string (s, "stream-format");
+
+ /* We can accept caps without alignment or format and will add them later on */
+ if (alignment && g_strcmp0 (alignment, "au")) {
+ return FALSE;
+ }
+
+ if (format && g_strcmp0 (format, "avc")) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+h264enc_complement (GstCaps * caps)
+{
+ gst_caps_set_simple (caps, "alignment", G_TYPE_STRING, "au",
+ "stream-format", G_TYPE_STRING, "avc", NULL);
+}
+
+static gboolean
+create_mpeg4vdec_codec_data_from_codec_data (GstDroidCodec *
+ codec G_GNUC_UNUSED, GstBuffer * data, DroidMediaData * out)
+{
+ /*
+ * If there are things which I hate the most, this function will be among them
+ * http://xhelmboyx.tripod.com/formats/mp4-layout.txt
+ */
+ GstMapInfo info;
+ GstByteWriter *writer = NULL;
+ codec->data->h264_nal = 0;
+
+ if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+ return FALSE;
+ }
+
+ writer = gst_byte_writer_new_with_size (info.size + 29 - 4, FALSE);
+#if 0 /* stagefright ESDS parser does not like us when we have the first 4 bytes */
+ gst_byte_writer_put_uint32_be (writer, 0); /* version and flags */
+#endif
+ gst_byte_writer_put_uint8 (writer, 0x03); /* ES descriptor type tag */
+ gst_byte_writer_put_uint8 (writer, 23 + info.size); /* size */
+ gst_byte_writer_put_uint16_be (writer, 0); /* ES ID */
+ gst_byte_writer_put_uint8 (writer, 0x1f); /* priority */
+ gst_byte_writer_put_uint8 (writer, 0x04); /* decoder config descriptor type tag */
+ gst_byte_writer_put_uint8 (writer, 15 + info.size);
+ gst_byte_writer_put_uint8 (writer, 0x20); /* object type: MPEG4 video */
+ gst_byte_writer_put_uint8 (writer, 0x11); /* stream type: visual stream */
+
+ /* buffer size db, average bit rate and max bit rate values are taken from stagefright MPEG4Writer */
+ gst_byte_writer_put_uint8 (writer, 0x01); /* buffer size db: 1/3 */
+ gst_byte_writer_put_uint8 (writer, 0x77); /* buffer size db: 2/3 */
+ gst_byte_writer_put_uint8 (writer, 0x00); /* buffer size db: 3/3 */
+ gst_byte_writer_put_uint8 (writer, 0x00); /* max bit rate: 1/4 */
+ gst_byte_writer_put_uint8 (writer, 0x03); /* max bit rate: 2/4 */
+ gst_byte_writer_put_uint8 (writer, 0xe8); /* max bit rate: 3/4 */
+ gst_byte_writer_put_uint8 (writer, 0x00); /* max bit rate: 4/4 */
+
+ gst_byte_writer_put_uint8 (writer, 0x00); /* average bit rate: 1/4 */
+ gst_byte_writer_put_uint8 (writer, 0x03); /* average bit rate: 2/4 */
+ gst_byte_writer_put_uint8 (writer, 0xe8); /* average bit rate: 3/4 */
+ gst_byte_writer_put_uint8 (writer, 0x00); /* average bit rate: 4/4 */
+
+ gst_byte_writer_put_uint8 (writer, 0x05); /* decoder specific descriptor type tag */
+ gst_byte_writer_put_uint8 (writer, info.size); /* size */
+ gst_byte_writer_put_data (writer, info.data, info.size); /* codec data */
+
+ gst_byte_writer_put_uint8 (writer, 0x06); /* SL config descriptor type tag */
+ gst_byte_writer_put_uint8 (writer, 0x01); /* descriptor type length */
+ gst_byte_writer_put_uint8 (writer, 0x02); /* SL value */
+
+ out->size = gst_byte_writer_get_size (writer);
+ out->data = gst_byte_writer_free_and_get_data (writer);
+
+ gst_buffer_unmap (data, &info);
+
+ return TRUE;
+}
+
+static gboolean
+create_vp8vdec_codec_data_from_codec_data (GstDroidCodec * codec,
+ GstBuffer * data, DroidMediaData * out)
+{
+ GstMapInfo info;
+ gboolean ret = FALSE;
+
+ if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+ return FALSE;
+ }
+
+ if (info.size < 7 || info.data[0] != 1) {
+ GST_ERROR ("malformed codec_data");
+ goto out;
+ }
+
+ out->size = info.size;
+ out->data = g_malloc (info.size);
+ memcpy (out->data, info.data, info.size);
+ ret = TRUE;
+
+out:
+ gst_buffer_unmap (data, &info);
+
+ return ret;
+}
+
+static gboolean
+create_h264dec_codec_data_from_codec_data (GstDroidCodec * codec,
+ GstBuffer * data, DroidMediaData * out)
+{
+ GstMapInfo info;
+ gboolean ret = FALSE;
+
+ if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+ return FALSE;
+ }
+
+ if (info.size < 7 || info.data[0] != 1) {
+ GST_ERROR ("malformed codec_data");
+ goto out;
+ }
+
+ codec->data->h264_nal = (1 + (info.data[4] & 3));
+
+ GST_INFO ("nal prefix length %d", codec->data->h264_nal);
+
+ out->size = info.size;
+ out->data = g_malloc (info.size);
+ memcpy (out->data, info.data, info.size);
+ ret = TRUE;
+
+out:
+ gst_buffer_unmap (data, &info);
+
+ return ret;
+}
+
+static int
+write_len (guint8 * buf, int val)
+{
+ /* This is some sort of variable-length coding, but the quicktime
+ * file(s) I have here all just use a 4-byte version, so we'll do that.
+ * Return the number of bytes written;
+ */
+ buf[0] = ((val >> 21) & 0x7f) | 0x80;
+ buf[1] = ((val >> 14) & 0x7f) | 0x80;
+ buf[2] = ((val >> 7) & 0x7f) | 0x80;
+ buf[3] = ((val >> 0) & 0x7f);
+ return 4;
+}
+
+static gboolean
+create_aacdec_codec_data_from_codec_data (GstDroidCodec * codec G_GNUC_UNUSED,
+ GstBuffer * data, DroidMediaData * out)
+{
+#define _QT_PUT(__data, __idx, __size, __shift, __num) \
+ (((guint8 *) (__data))[__idx] = (((guint##__size) __num) >> __shift) & 0xff)
+#define QT_WRITE_UINT24(data, num) do { \
+ _QT_PUT (data, 0, 32, 0, num); \
+ _QT_PUT (data, 1, 32, 8, num); \
+ _QT_PUT (data, 2, 32, 16, num); \
+} while (0)
+
+ GstMapInfo info;
+ gboolean ret;
+
+ /*
+ * blindly based on audiodecoders.c:make_aac_magic_cookie()
+ */
+
+ if (!gst_buffer_map (data, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+
+ ret = FALSE;
+ goto out;
+ }
+
+ int offset = 0;
+ int decoder_specific_len = info.size;
+ int config_len = 13 + 5 + decoder_specific_len;
+ int es_len = 3 + 5 + config_len + 5 + 1;
+ int total_len = es_len + 5;
+
+ out->size = total_len;
+ out->data = g_malloc0 (out->size);
+
+ /* Structured something like this:
+ * [ES Descriptor
+ * [Config Descriptor
+ * [Specific Descriptor]]
+ * [Unknown]]
+ */
+
+ GST_WRITE_UINT8 (out->data + offset, 0x03);
+ offset += 1; /* ES Descriptor tag */
+ offset += write_len (out->data + offset, es_len);
+ GST_WRITE_UINT16_LE (out->data + offset, 0);
+ offset += 2; /* Track ID */
+ GST_WRITE_UINT8 (out->data + offset, 0);
+ offset += 1; /* Flags */
+
+ GST_WRITE_UINT8 (out->data + offset, 0x04);
+ offset += 1; /* Config Descriptor tag */
+ offset += write_len (out->data + offset, config_len);
+
+ /* TODO: Fix these up */
+ GST_WRITE_UINT8 (out->data + offset, 0x40);
+ offset += 1; /* object_type_id */
+ GST_WRITE_UINT8 (out->data + offset, 0x15);
+ offset += 1; /* stream_type */
+ QT_WRITE_UINT24 (out->data + offset, 0x1800);
+ offset += 3; /* buffer_size_db */
+ GST_WRITE_UINT32_LE (out->data + offset, 128000);
+ offset += 4; /* max_bitrate */
+ GST_WRITE_UINT32_LE (out->data + offset, 128000);
+ offset += 4; /* avg_bitrate */
+
+ GST_WRITE_UINT8 (out->data + offset, 0x05);
+ offset += 1; /* Specific Descriptor tag */
+ offset += write_len (out->data + offset, decoder_specific_len);
+ memcpy (out->data + offset, info.data, decoder_specific_len);
+ offset += decoder_specific_len;
+
+ /* TODO: What is this? 'SL descriptor' apparently, but what does that mean? */
+ GST_WRITE_UINT8 (out->data + offset, 0x06);
+ offset += 1; /* SL Descriptor tag */
+ offset += write_len (out->data + offset, 1);
+ GST_WRITE_UINT8 (out->data + offset, 2);
+ offset += 1;
+
+ gst_buffer_unmap (data, &info);
+
+ ret = TRUE;
+
+out:
+ return ret;
+}
+
+static gboolean
+create_aacdec_codec_data_from_frame_data (GstDroidCodec * codec,
+ GstBuffer * frame_data, DroidMediaData * out)
+{
+ GstMapInfo info;
+ gboolean ret;
+ GstBuffer *data;
+
+ guint8 codec_data[2];
+ guint16 codec_data_data;
+ gint sr_idx;
+ gint object;
+ gint channels;
+
+ if (!codec->data->aac_adts) {
+ GST_ERROR ("not ADTS stream");
+ return FALSE;
+ }
+
+ /* stolen from gstaacparse.c */
+
+ GST_INFO ("constructing ADTS codec_data");
+
+ // TODO: size, TODO: error
+ if (!gst_buffer_map (frame_data, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+ return FALSE;
+ }
+
+ sr_idx = (info.data[2] & 0x3c) >> 2;
+ object = ((info.data[2] & 0xc0) >> 6) + 1;
+ channels = ((info.data[2] & 0x01) << 2) | ((info.data[3] & 0xc0) >> 6);
+ GST_INFO ("AAC info: sample rate index: %d, object type: %d, channels: %d",
+ sr_idx, object, channels);
+ gst_buffer_unmap (frame_data, &info);
+
+ codec_data_data = (object << 11) | sr_idx << 7 | channels << 3;
+
+ GST_WRITE_UINT16_BE (codec_data, codec_data_data);
+
+ data = gst_buffer_new_and_alloc (2);
+ gst_buffer_fill (data, 0, codec_data, 2);
+
+ ret = create_aacdec_codec_data_from_codec_data (codec, data, out);
+
+ gst_buffer_unref (data);
+
+ return ret;
+}
+
+static gboolean
+process_h264dec_data (GstDroidCodec * codec, GstBuffer * buffer,
+ DroidMediaData * out)
+{
+ GstMapInfo info;
+ gboolean ret = FALSE;
+ GstByteReader reader;
+ GstByteWriter *writer = NULL;
+
+ if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+ return FALSE;
+ }
+
+ if (info.size < codec->data->h264_nal) {
+ GST_ERROR ("malformed data");
+ goto out;
+ }
+
+ /* initial validation */
+ switch (codec->data->h264_nal) {
+ case 4:
+ case 2:
+ case 3:
+ case 1:
+ break;
+
+ default:
+ GST_ERROR ("unhandled nal prefix size %d", codec->data->h264_nal);
+ goto out;
+ }
+
+ gst_byte_reader_init (&reader, info.data, info.size);
+
+ /* info.size is our best estimate and should be correct if nal prefix is 4 bytes which is most of the cases */
+ writer = gst_byte_writer_new_with_size (info.size, FALSE);
+
+ while (gst_byte_reader_get_pos (&reader) < info.size) {
+ guint len = 0;
+ guint16 len16 = 0;
+ guint8 len8 = 0;
+ gboolean success = FALSE;
+ const guint8 *data = NULL;
+
+ switch (codec->data->h264_nal) {
+ case 4:
+ success = gst_byte_reader_get_uint32_be (&reader, &len);
+ break;
+
+ case 3:
+ success = gst_byte_reader_get_uint24_be (&reader, &len);
+ break;
+
+ case 2:
+ success = gst_byte_reader_get_uint16_be (&reader, &len16);
+ len = len16;
+ break;
+
+ case 1:
+ success = gst_byte_reader_get_uint8 (&reader, &len8);
+ len = len8;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (!success) {
+ GST_ERROR ("malformed NAL");
+ goto out;
+ }
+
+ if (!gst_byte_writer_put_data (writer, (guint8 *) "\x00\x00\x00\x01", 4)) {
+ GST_ERROR ("failed to write NAL prefix");
+ goto out;
+ }
+
+ if (!gst_byte_reader_get_data (&reader, len, &data)) {
+ GST_ERROR ("failed to read NAL");
+ goto out;
+ }
+
+ if (!gst_byte_writer_put_data (writer, data, len)) {
+ GST_ERROR ("failed to write NAL");
+ goto out;
+ }
+
+ GST_LOG ("parsed nal unit of size %d", len);
+ }
+
+ out->size = gst_byte_writer_get_size (writer);
+ out->data = gst_byte_writer_free_and_get_data (writer);
+ writer = NULL;
+ ret = TRUE;
+
+out:
+ if (writer) {
+ gst_byte_writer_free (writer);
+ writer = NULL;
+ }
+
+ gst_buffer_unmap (buffer, &info);
+
+ return ret;
+}
+
+static gboolean
+process_aacdec_data (GstDroidCodec * codec, GstBuffer * buffer,
+ DroidMediaData * out)
+{
+ GstMapInfo info;
+
+ if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
+ GST_ERROR ("failed to map buffer");
+ return FALSE;
+ }
+
+ if (!codec->data->aac_adts) {
+ out->size = info.size;
+ out->data = g_malloc (info.size);
+ memcpy (out->data, info.data, info.size);
+ } else {
+ /* stolen from gstaacparse.c */
+ guint header_size = (info.data[1] & 1) ? 7 : 9; /* optional CRC */
+ out->size = info.size - header_size;
+ out->data = g_malloc (out->size);
+ memcpy (out->data, info.data + header_size, out->size);
+ GST_LOG ("stripping %d bytes", header_size);
+ }
+
+ gst_buffer_unmap (buffer, &info);
+
+ return TRUE;
+}
+
+static gboolean
+process_h264enc_data (DroidMediaData * in, DroidMediaData * out)
+{
+ guint32 size;
+ guint8 *data;
+
+ if (in->size >= 4 && memcmp (in->data, "\x00\x00\x00\x01", 4) == 0) {
+ /* We will replace the first 4 bytes with the NAL size */
+ out->size = in->size;
+ data = in->data + 4;
+ } else {
+ /* We don't have the NAL prefix so we add 4 bytes for the NAL size */
+ out->size = in->size + 4;
+ data = in->data;
+ }
+
+ size = GUINT32_TO_BE (out->size - 4);
+ out->data = g_malloc (out->size);
+ if (!out->data) {
+ return FALSE;
+ }
+
+ memcpy (out->data, &size, sizeof (size));
+ memcpy (out->data + 4, data, out->size - 4);
+
+ return TRUE;
+}
+
+static void
+gst_droid_codec_release_input_frame (void *data)
+{
+ GstDroidCodecFrameReleaseData *info = (GstDroidCodecFrameReleaseData *) data;
+
+ g_free (info->data);
+
+ g_slice_free (GstDroidCodecFrameReleaseData, info);
+}
+
+static void
+gst_droid_codec_type_fill_quirks (GstDroidCodec * codec)
+{
+ GKeyFile *file = g_key_file_new ();
+ gchar *path = g_strdup_printf ("%s/gst-droid/gstdroidcodec.conf", SYSCONFDIR);
+ gchar **quirks_string = NULL;
+ const gchar *group
+ = (codec->info->type == GST_DROID_CODEC_DECODER_AUDIO
+ || codec->info->type ==
+ GST_DROID_CODEC_DECODER_VIDEO) ? "decoder-quirks" : "encoder-quirks";
+ gsize quirks_length = 0;
+ int x;
+
+ g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
+ g_free (path);
+
+ if (!g_key_file_has_group (file, group)) {
+ GST_LOG ("no quirks");
+ goto out;
+ }
+
+ quirks_string =
+ g_key_file_get_string_list (file, group, codec->info->droid,
+ &quirks_length, NULL);
+ if (!quirks_string) {
+ GST_LOG ("no quirks for %s", codec->info->droid);
+ goto out;
+ }
+
+ for (x = 0; x < quirks_length; x++) {
+ if (!g_strcmp0 (quirks_string[x], USE_CODEC_SUPPLIED_HEIGHT_NAME)) {
+ codec->quirks |= USE_CODEC_SUPPLIED_HEIGHT_VALUE;
+ } else if (!g_strcmp0 (quirks_string[x], USE_CODEC_SUPPLIED_WIDTH_NAME)) {
+ codec->quirks |= USE_CODEC_SUPPLIED_WIDTH_VALUE;
+ }
+ }
+
+out:
+ g_key_file_free (file);
+ file = NULL;
+
+ if (quirks_string) {
+ g_strfreev (quirks_string);
+ quirks_string = NULL;
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst-libs/gst/droid/gstdroidcodec.h
^
|
(renamed from gst/droidcodec/gstdroidcodec.h)
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/Makefile.am
^
|
@@ -19,7 +19,8 @@
gstdroidcamsrcphotography.c \
gstdroidcamsrcquirks.c \
gstdroidcamsrcexif.c \
- gstdroidcamsrcmode.c
+ gstdroidcamsrcmode.c \
+ gstdroidcamsrcrecorder.c
noinst_HEADERS = \
gstdroidcamsrc.h \
@@ -29,4 +30,5 @@
gstdroidcamsrcphotography.h \
gstdroidcamsrcquirks.h \
gstdroidcamsrcexif.h \
- gstdroidcamsrcmode.h
+ gstdroidcamsrcmode.h \
+ gstdroidcamsrcrecorder.h
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrc.c
^
|
@@ -30,7 +30,9 @@
#include "gst/droid/gstdroidmediabuffer.h"
#include "gst/droid/gstwrappedmemory.h"
#include "gst/droid/gstdroidquery.h"
+#include "gst/droid/gstdroidcodec.h"
#include "gstdroidcamsrcphotography.h"
+#include "gstdroidcamsrcrecorder.h"
#include "droidmediacamera.h"
#ifndef GST_USE_UNSTABLE_API
#define GST_USE_UNSTABLE_API
@@ -59,12 +61,14 @@
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("image/jpeg"));
+#if 0
static GstStaticPadTemplate vid_src_template_factory =
GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME,
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_DROID_VIDEO_META_DATA, "{YV12}")));
+#endif
static gboolean gst_droidcamsrc_pad_activate_mode (GstPad * pad,
GstObject * parent, GstPadMode mode, gboolean active);
@@ -86,6 +90,7 @@
static gchar *gst_droidcamsrc_find_picture_resolution (GstDroidCamSrc * src,
const gchar * resolution);
static gboolean gst_droidcamsrc_is_zsl_and_hdr_supported (GstDroidCamSrc * src);
+static GstCaps *gst_droidcamsrc_get_video_caps_locked (GstDroidCamSrc * src);
enum
{
@@ -108,14 +113,16 @@
#define DEFAULT_IMAGE_NOISE_REDUCTION TRUE
#define DEFAULT_SENSOR_ORIENTATION 0
#define DEFAULT_IMAGE_MODE GST_DROIDCAMSRC_IMAGE_MODE_NORMAL
+#define DEFAULT_TARGET_BITRATE 12000000
static GstDroidCamSrcPad *
-gst_droidcamsrc_create_pad (GstDroidCamSrc * src, GstStaticPadTemplate * tpl,
+gst_droidcamsrc_create_pad (GstDroidCamSrc * src,
const gchar * name, gboolean capture_pad)
{
GstDroidCamSrcPad *pad = g_slice_new0 (GstDroidCamSrcPad);
-
- pad->pad = gst_pad_new_from_static_template (tpl, name);
+ GstPadTemplate *tpl =
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (src), name);
+ pad->pad = gst_pad_new_from_template (tpl, name);
/* TODO: I don't think this is needed */
gst_pad_use_fixed_caps (pad->pad);
@@ -174,19 +181,20 @@
src->height = 0;
src->fps_n = 0;
src->fps_d = 1;
+ src->target_bitrate = DEFAULT_TARGET_BITRATE;
gst_droidcamsrc_photography_init (src, DEFAULT_CAMERA_DEVICE);
src->vfsrc = gst_droidcamsrc_create_pad (src,
- &vf_src_template_factory, GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME, FALSE);
+ GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME, FALSE);
src->vfsrc->negotiate = gst_droidcamsrc_vfsrc_negotiate;
src->imgsrc = gst_droidcamsrc_create_pad (src,
- &img_src_template_factory, GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME, TRUE);
+ GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME, TRUE);
src->imgsrc->negotiate = gst_droidcamsrc_imgsrc_negotiate;
src->vidsrc = gst_droidcamsrc_create_pad (src,
- &vid_src_template_factory, GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME, TRUE);
+ GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME, TRUE);
src->vidsrc->adjust_segment = TRUE;
src->vidsrc->negotiate = gst_droidcamsrc_vidsrc_negotiate;
@@ -288,6 +296,10 @@
g_value_set_pointer (value, supported_image_modes);
break;
+ case PROP_TARGET_BITRATE:
+ g_value_set_int (value, src->target_bitrate);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -384,6 +396,10 @@
gst_droidcamsrc_apply_mode_settings (src, SET_AND_APPLY);
break;
+ case PROP_TARGET_BITRATE:
+ src->target_bitrate = g_value_get_int (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -907,6 +923,8 @@
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
+ GstCaps *caps;
+ GstPadTemplate *tpl;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
@@ -921,8 +939,18 @@
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&img_src_template_factory));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&vid_src_template_factory));
+ /* encoded caps */
+ caps = gst_droid_codec_get_all_caps (GST_DROID_CODEC_ENCODER_VIDEO);
+
+ /* add raw caps */
+ caps =
+ gst_caps_merge (caps,
+ gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
+ (GST_CAPS_FEATURE_MEMORY_DROID_VIDEO_META_DATA, "{YV12}")));
+ tpl =
+ gst_pad_template_new (GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME, GST_PAD_SRC,
+ GST_PAD_ALWAYS, caps);
+ gst_element_class_add_pad_template (gstelement_class, tpl);
gobject_class->set_property = gst_droidcamsrc_set_property;
gobject_class->get_property = gst_droidcamsrc_get_property;
@@ -1014,6 +1042,11 @@
"Image modes supported by HAL",
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_TARGET_BITRATE,
+ g_param_spec_int ("target-bitrate", "Target Bitrate",
+ "Target bitrate", 0, G_MAXINT,
+ DEFAULT_TARGET_BITRATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
gst_droidcamsrc_photography_add_overrides (gobject_class);
/* Signals */
@@ -1393,7 +1426,7 @@
} else if (data == src->imgsrc) {
caps = gst_droidcamsrc_params_get_image_caps (src->dev->params);
} else if (data == src->vidsrc) {
- caps = gst_droidcamsrc_params_get_video_caps (src->dev->params);
+ caps = gst_droidcamsrc_get_video_caps_locked (src);
}
} else {
caps = gst_pad_get_pad_template_caps (data->pad);
@@ -1633,7 +1666,7 @@
GST_DEBUG_OBJECT (src, "vidsrc negotiate");
- our_caps = gst_droidcamsrc_params_get_video_caps (src->dev->params);
+ our_caps = gst_droidcamsrc_get_video_caps_locked (src);
GST_DEBUG_OBJECT (src, "our caps %" GST_PTR_FORMAT, our_caps);
if (!our_caps || gst_caps_is_empty (our_caps)) {
@@ -1679,7 +1712,10 @@
}
vid = g_strdup_printf ("%ix%i", info.width, info.height);
- gst_droidcamsrc_params_set_string (src->dev->params, "video-size", vid);
+ gchar *key =
+ src->dev->
+ params->has_separate_video_size_values ? "video-size" : "preview-size";
+ gst_droidcamsrc_params_set_string (src->dev->params, key, vid);
/* Now we need to find a picture size that is equal to our video size.
* Some devices need to have a picture size otherwise the video mode viewfinder
@@ -1694,6 +1730,16 @@
ret = TRUE;
+ if (info.finfo->format == GST_VIDEO_FORMAT_ENCODED) {
+ GST_INFO_OBJECT (src, "using external recorder");
+ src->dev->use_recorder = TRUE;
+ } else {
+ GST_INFO_OBJECT (src, "using raw recorder");
+ src->dev->use_recorder = FALSE;
+ }
+
+ gst_droidcamsrc_recorder_update_vid (src->dev->recorder, &info, our_caps);
+
out:
if (peer) {
gst_caps_unref (peer);
@@ -2271,3 +2317,58 @@
GST_INFO_OBJECT (src, "zsl and hdr supported: %d", ret);
return ret;
}
+
+static GstCaps *
+gst_droidcamsrc_get_video_caps_locked (GstDroidCamSrc * src)
+{
+ struct Data
+ {
+ GstCaps *result;
+ GstStructure *encoded;
+ };
+
+ gboolean __map (GstCapsFeatures * features,
+ GstStructure * structure, struct Data *data)
+ {
+
+ /* Given structure from template caps, we need to transform Data::encoded */
+ int i;
+ GstStructure *s = gst_structure_copy (data->encoded);
+ for (i = 0; i < gst_structure_n_fields (structure); i++) {
+ const gchar *field = gst_structure_nth_field_name (structure, i);
+ /* skip format field */
+ if (g_strcmp0 (field, "format") != 0) {
+ gst_structure_set_value (s, field, gst_structure_get_value (structure,
+ field));
+ }
+ }
+
+ data->result = gst_caps_merge_structure (data->result, s);
+
+ return TRUE;
+ }
+
+ GstCaps *tpl = gst_droidcamsrc_params_get_video_caps (src->dev->params);
+ GstCaps *caps = gst_caps_new_empty ();
+ GstCaps *encoded =
+ gst_droid_codec_get_all_caps (GST_DROID_CODEC_ENCODER_VIDEO);
+ int x;
+
+ struct Data data;
+ data.result = caps;
+
+ for (x = 0; x < gst_caps_get_size (encoded); x++) {
+ data.encoded = gst_caps_get_structure (encoded, x);
+ gst_caps_foreach (tpl, __map, &data);
+ }
+
+ caps = gst_caps_merge (caps, tpl);
+
+ caps = gst_caps_simplify (caps);
+
+ gst_caps_unref (encoded);
+
+ GST_DEBUG_OBJECT (src, "video caps %" GST_PTR_FORMAT, caps);
+
+ return caps;
+}
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrc.h
^
|
@@ -120,6 +120,8 @@
gfloat max_ev_compensation;
gfloat ev_step;
+ gint32 target_bitrate;
+
/* protected with OBJECT_LOCK */
gint width;
gint height;
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrcdev.c
^
|
@@ -26,6 +26,7 @@
#include "gstdroidcamsrcdev.h"
#include <stdlib.h>
#include "gstdroidcamsrc.h"
+#include "gstdroidcamsrcrecorder.h"
#include "gst/droid/gstdroidmediabuffer.h"
#include "gst/droid/gstwrappedmemory.h"
#include "gst/droid/gstdroidbufferpool.h"
@@ -73,6 +74,13 @@
static void
gst_droidcamsrc_dev_prepare_buffer (GstDroidCamSrcDev * dev, GstBuffer * buffer,
DroidMediaRect rect, int width, int height, GstVideoFormat format);
+static gboolean
+gst_droidcamsrc_dev_start_video_recording_recorder_locked (GstDroidCamSrcDev *
+ dev);
+static gboolean
+gst_droidcamsrc_dev_start_video_recording_raw_locked (GstDroidCamSrcDev * dev);
+static void gst_droidcamsrc_dev_queue_video_buffer_locked (GstDroidCamSrcDev *
+ dev, GstBuffer * buffer);
static void
gst_droidcamsrc_dev_shutter_callback (void *user)
@@ -309,7 +317,6 @@
GstBuffer *buffer;
GstMemory *mem;
GstDroidCamSrcDevVideoData *mem_data;
- gboolean drop_buffer;
GST_DEBUG_OBJECT (src, "dev video frame callback");
@@ -335,26 +342,12 @@
(GFunc) gst_droidcamsrc_dev_release_recording_frame, mem_data);
gst_buffer_insert_memory (buffer, 0, mem);
- GST_BUFFER_OFFSET (buffer) = dev->vid->video_frames;
- GST_BUFFER_OFFSET_END (buffer) = ++dev->vid->video_frames;
gst_droidcamsrc_timestamp (src, buffer);
- g_rec_mutex_lock (dev->lock);
- ++dev->vid->queued_frames;
- g_rec_mutex_unlock (dev->lock);
-
- drop_buffer = !dev->vid->running;
+ gst_droidcamsrc_dev_queue_video_buffer_locked (dev, buffer);
- if (drop_buffer) {
- GST_INFO_OBJECT (src,
- "dropping buffer because video recording is not running");
- gst_buffer_unref (buffer);
- } else {
- g_mutex_lock (&dev->vidsrc->lock);
- g_queue_push_tail (dev->vidsrc->queue, buffer);
- g_cond_signal (&dev->vidsrc->cond);
- g_mutex_unlock (&dev->vidsrc->lock);
- }
+ g_mutex_unlock (&dev->vid->lock);
+ return;
unlock_and_out:
/* in case stop_video_recording() is waiting for us */
@@ -543,6 +536,9 @@
dev->pool = gst_droid_buffer_pool_new ();
+ dev->use_recorder = FALSE;
+ dev->recorder = gst_droidcamsrc_recorder_create (vidsrc);
+
droid_media_camera_constants_init (&dev->c);
return dev;
@@ -624,6 +620,8 @@
gst_object_unref (dev->pool);
+ gst_droidcamsrc_recorder_destroy (dev->recorder);
+
g_slice_free (GstDroidCamSrcImageCaptureState, dev->img);
g_slice_free (GstDroidCamSrcVideoCaptureState, dev->vid);
g_slice_free (GstDroidCamSrcDev, dev);
@@ -873,18 +871,14 @@
dev->vid->video_frames = 0;
dev->vid->queued_frames = 0;
- /* TODO: get that from caps */
- if (!droid_media_camera_store_meta_data_in_buffers (dev->cam, true)) {
- GST_ELEMENT_ERROR (src, LIBRARY, SETTINGS,
- ("error storing meta data in buffers for video recording"), (NULL));
- goto out;
+ if (dev->use_recorder) {
+ ret = gst_droidcamsrc_dev_start_video_recording_recorder_locked (dev);
+ } else {
+ ret = gst_droidcamsrc_dev_start_video_recording_raw_locked (dev);
}
- if (!droid_media_camera_start_recording (dev->cam)) {
- GST_ELEMENT_ERROR (src, LIBRARY, FAILED, ("error starting video recording"),
- (NULL));
+ if (!ret)
goto out;
- }
ret = TRUE;
@@ -931,21 +925,28 @@
GST_ERROR ("failed to push EOS event");
}
- g_rec_mutex_lock (dev->lock);
+ if (!dev->use_recorder) {
+ g_rec_mutex_lock (dev->lock);
- GST_INFO ("waiting for queued frames %i", dev->vid->queued_frames);
+ GST_INFO ("waiting for queued frames %i", dev->vid->queued_frames);
- while (dev->vid->queued_frames > 0) {
- GST_INFO ("waiting for queued frames to reach 0 from %i",
- dev->vid->queued_frames);
+ while (dev->vid->queued_frames > 0) {
+ GST_INFO ("waiting for queued frames to reach 0 from %i",
+ dev->vid->queued_frames);
+ g_rec_mutex_unlock (dev->lock);
+ usleep (VIDEO_RECORDING_STOP_TIMEOUT);
+ g_rec_mutex_lock (dev->lock);
+ }
+
+ /* TODO: move this unlock() call after we stop recording? */
g_rec_mutex_unlock (dev->lock);
- usleep (VIDEO_RECORDING_STOP_TIMEOUT);
- g_rec_mutex_lock (dev->lock);
}
- g_rec_mutex_unlock (dev->lock);
-
- droid_media_camera_stop_recording (dev->cam);
+ if (dev->use_recorder) {
+ gst_droidcamsrc_recorder_stop (dev->recorder);
+ } else {
+ droid_media_camera_stop_recording (dev->cam);
+ }
gst_buffer_pool_set_flushing (dev->pool, FALSE);
@@ -1138,3 +1139,86 @@
GST_LOG_OBJECT (src, "preview info: w=%d, h=%d, crop: x=%d, y=%d, w=%d, h=%d",
width, height, crop->x, crop->y, crop->width, crop->height);
}
+
+static gboolean
+gst_droidcamsrc_dev_start_video_recording_recorder_locked (GstDroidCamSrcDev *
+ dev)
+{
+ GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
+
+ if (!gst_droidcamsrc_recorder_init (dev->recorder, dev->cam,
+ src->target_bitrate)) {
+ GST_ELEMENT_ERROR (src, LIBRARY, FAILED,
+ ("error initializing video recorder"), (NULL));
+ return FALSE;
+ }
+
+ if (!gst_droidcamsrc_recorder_start (dev->recorder)) {
+ GST_ELEMENT_ERROR (src, LIBRARY, FAILED, ("error starting video recorder"),
+ (NULL));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_droidcamsrc_dev_start_video_recording_raw_locked (GstDroidCamSrcDev * dev)
+{
+ GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
+
+ /* TODO: get that from caps */
+ if (!droid_media_camera_store_meta_data_in_buffers (dev->cam, true)) {
+ GST_ELEMENT_ERROR (src, LIBRARY, SETTINGS,
+ ("error storing meta data in buffers for video recording"), (NULL));
+ return FALSE;
+ }
+
+ if (!droid_media_camera_start_recording (dev->cam)) {
+ GST_ELEMENT_ERROR (src, LIBRARY, FAILED, ("error starting video recording"),
+ (NULL));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+gst_droidcamsrc_dev_queue_video_buffer (GstDroidCamSrcDev * dev,
+ GstBuffer * buffer)
+{
+ g_mutex_lock (&dev->vid->lock);
+ gst_droidcamsrc_dev_queue_video_buffer_locked (dev, buffer);
+ g_mutex_unlock (&dev->vid->lock);
+}
+
+static void
+gst_droidcamsrc_dev_queue_video_buffer_locked (GstDroidCamSrcDev * dev,
+ GstBuffer * buffer)
+{
+ GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
+ gboolean drop_buffer;
+
+ GST_BUFFER_OFFSET (buffer) = dev->vid->video_frames;
+ GST_BUFFER_OFFSET_END (buffer) = ++dev->vid->video_frames;
+
+ g_rec_mutex_lock (dev->lock);
+ ++dev->vid->queued_frames;
+ g_rec_mutex_unlock (dev->lock);
+
+ drop_buffer = !dev->vid->running;
+
+ if (drop_buffer) {
+ GST_INFO_OBJECT (src,
+ "dropping buffer because video recording is not running");
+ gst_buffer_unref (buffer);
+ } else {
+ g_mutex_lock (&dev->vidsrc->lock);
+ g_queue_push_tail (dev->vidsrc->queue, buffer);
+ g_cond_signal (&dev->vidsrc->cond);
+ g_mutex_unlock (&dev->vidsrc->lock);
+ }
+
+ /* in case stop_video_recording() is waiting for us */
+ g_cond_signal (&dev->vid->cond);
+}
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrcdev.h
^
|
@@ -2,7 +2,7 @@
* gst-droid
*
* Copyright (C) 2014 Mohammed Sameer <msameer@foolab.org>
- * Copyright (C) 2015 Jolla LTD.
+ * Copyright (C) 2015-2016 Jolla LTD.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,6 +34,7 @@
typedef struct _GstDroidCamSrcVideoCaptureState GstDroidCamSrcVideoCaptureState;
typedef struct _GstDroidCamSrcCamInfo GstDroidCamSrcCamInfo;
typedef struct _GstDroidCamSrcPad GstDroidCamSrcPad;
+typedef struct _GstDroidCamSrcRecorder GstDroidCamSrcRecorder;
struct _GstDroidCamSrcDev
{
@@ -53,6 +54,9 @@
GstDroidCamSrcVideoCaptureState *vid;
GstBufferPool *pool;
DroidMediaCameraConstants c;
+
+ gboolean use_recorder;
+ GstDroidCamSrcRecorder *recorder;
};
GstDroidCamSrcDev *gst_droidcamsrc_dev_new (GstDroidCamSrcPad *vfsrc,
@@ -88,6 +92,8 @@
gboolean gst_droidcamsrc_dev_is_running (GstDroidCamSrcDev * dev);
+void gst_droidcamsrc_dev_queue_video_buffer (GstDroidCamSrcDev * dev, GstBuffer * buffer);
+
G_END_DECLS
#endif /* __GST_DROIDCAMSRC_DEV_H__ */
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrcparams.c
^
|
@@ -195,6 +195,8 @@
gst_droidcamsrc_params_fill_fps_range_arrays_locked (params);
params->is_dirty = FALSE;
+ params->has_separate_video_size_values =
+ g_hash_table_lookup (params->params, "video-size-values") != NULL;
}
GstDroidCamSrcParams *
@@ -389,8 +391,14 @@
GstCaps *caps;
g_mutex_lock (¶ms->lock);
- caps = gst_droidcamsrc_params_get_caps_locked (params, "video-size-values",
+
+ gchar *key =
+ params->has_separate_video_size_values ? "video-size-values" :
+ "preview-size-values";
+
+ caps = gst_droidcamsrc_params_get_caps_locked (params, key,
"video/x-raw", GST_CAPS_FEATURE_MEMORY_DROID_VIDEO_META_DATA, "YV12");
+
g_mutex_unlock (¶ms->lock);
return caps;
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrcparams.h
^
|
@@ -32,6 +32,7 @@
GHashTable *params;
gboolean is_dirty;
GArray *min_fps_range, *max_fps_range;
+ gboolean has_separate_video_size_values;
GMutex lock;
};
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrcphotography.h
^
|
@@ -46,6 +46,7 @@
PROP_IMAGE_NOISE_REDUCTION,
PROP_SENSOR_ORIENTATION,
PROP_SENSOR_MOUNT_ANGLE,
+ PROP_TARGET_BITRATE,
/* photography interface */
PROP_WB_MODE,
|
[-]
[+]
|
Added |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrcrecorder.c
^
|
@@ -0,0 +1,173 @@
+/*
+ * gst-droid
+ *
+ * Copyright (C) 2016 Jolla LTD.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "gstdroidcamsrcrecorder.h"
+#include "gstdroidcamsrc.h"
+#include <gst/droid/gstdroidcodec.h>
+
+#define GST_DROIDCAMSRC_RECORDER_TARGET_BITRATE_DEFAULT 192000
+
+static void gst_droidcamsrc_recorder_data_available (void *data,
+ DroidMediaCodecData * encoded);
+
+GstDroidCamSrcRecorder *
+gst_droidcamsrc_recorder_create (GstDroidCamSrcPad * vidsrc)
+{
+ GstDroidCamSrcRecorder *recorder = g_new0 (GstDroidCamSrcRecorder, 1);
+
+ recorder->vidsrc = vidsrc;
+ recorder->md.bitrate = GST_DROIDCAMSRC_RECORDER_TARGET_BITRATE_DEFAULT;
+ recorder->md.meta_data = true;
+ recorder->md.parent.flags = DROID_MEDIA_CODEC_HW_ONLY;
+
+ return recorder;
+}
+
+void
+gst_droidcamsrc_recorder_destroy (GstDroidCamSrcRecorder * recorder)
+{
+ if (recorder->codec) {
+ gst_droid_codec_unref (recorder->codec);
+ }
+
+ g_free (recorder);
+}
+
+gboolean
+gst_droidcamsrc_recorder_init (GstDroidCamSrcRecorder * recorder,
+ DroidMediaCamera * cam, gint32 target_bitrate)
+{
+ if (!recorder->codec) {
+ return FALSE;
+ }
+
+ if (recorder->recorder) {
+ droid_media_recorder_destroy (recorder->recorder);
+ }
+
+ recorder->md.bitrate = target_bitrate;
+
+ recorder->recorder = droid_media_recorder_create (cam, &recorder->md);
+
+ if (!recorder->recorder) {
+ return FALSE;
+ }
+
+ DroidMediaCodecDataCallbacks cb;
+ cb.data_available = gst_droidcamsrc_recorder_data_available;
+
+ droid_media_recorder_set_data_callbacks (recorder->recorder, &cb, recorder);
+
+ return TRUE;
+}
+
+void
+gst_droidcamsrc_recorder_update_vid (GstDroidCamSrcRecorder * recorder,
+ GstVideoInfo * info, GstCaps * caps)
+{
+ recorder->codec =
+ gst_droid_codec_new_from_caps (caps, GST_DROID_CODEC_ENCODER_VIDEO);
+ recorder->md.parent.width = info->width;
+ recorder->md.parent.height = info->height;
+ recorder->md.stride = recorder->md.parent.width;
+ recorder->md.slice_height = recorder->md.parent.height;
+ recorder->md.parent.fps = info->fps_n / info->fps_d;
+
+ if (recorder->codec) {
+ recorder->md.parent.type = gst_droid_codec_get_droid_type (recorder->codec);
+ }
+}
+
+gboolean
+gst_droidcamsrc_recorder_start (GstDroidCamSrcRecorder * recorder)
+{
+ return droid_media_recorder_start (recorder->recorder);
+}
+
+void
+gst_droidcamsrc_recorder_stop (GstDroidCamSrcRecorder * recorder)
+{
+ droid_media_recorder_stop (recorder->recorder);
+}
+
+static void
+gst_droidcamsrc_recorder_data_available (void *data,
+ DroidMediaCodecData * encoded)
+{
+ GstDroidCamSrcRecorder *recorder = (GstDroidCamSrcRecorder *) data;
+ GstDroidCamSrc *src =
+ GST_DROIDCAMSRC (GST_PAD_PARENT (recorder->vidsrc->pad));
+ GstBuffer *buffer = NULL;
+
+ if (encoded->codec_config) {
+ GstBuffer *codec_data = NULL;
+ GstCaps *caps = NULL;
+ GstCaps *current;
+ gboolean ret;
+
+ codec_data =
+ gst_droid_codec_create_encoder_codec_data (recorder->codec,
+ &encoded->data);
+
+ if (!codec_data) {
+ GST_ELEMENT_ERROR (src, STREAM, FORMAT, (NULL),
+ ("Failed to construct codec_data. Expect corrupted stream"));
+ return;
+ }
+
+ current = gst_pad_get_current_caps (recorder->vidsrc->pad);
+ caps = gst_caps_copy (current);
+ gst_caps_unref (current);
+ current = NULL;
+
+ gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+ ret = gst_pad_set_caps (recorder->vidsrc->pad, caps);
+ gst_caps_unref (caps);
+
+ if (!ret) {
+ GST_ELEMENT_ERROR (src, STREAM, FORMAT, (NULL),
+ ("Failed to set video caps"));
+ }
+
+ return;
+ }
+
+ buffer =
+ gst_droid_codec_prepare_encoded_data (recorder->codec, &encoded->data);
+ if (!buffer) {
+ GST_ELEMENT_ERROR (src, LIBRARY, ENCODE, (NULL),
+ ("failed to process encoded data"));
+ return;
+ }
+
+ GST_BUFFER_PTS (buffer) = encoded->ts;
+ GST_BUFFER_DTS (buffer) = encoded->decoding_ts;
+
+ if (encoded->sync) {
+ GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+ } else {
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+
+ gst_droidcamsrc_dev_queue_video_buffer (src->dev, buffer);
+}
|
[-]
[+]
|
Added |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcamsrc/gstdroidcamsrcrecorder.h
^
|
@@ -0,0 +1,56 @@
+/*
+ * gst-droid
+ *
+ * Copyright (C) 2016 Jolla LTD.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_DROIDCAMSRC_RECORDER_H__
+#define __GST_DROIDCAMSRC_RECORDER_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <droidmediarecorder.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstDroidCamSrcRecorder GstDroidCamSrcRecorder;
+typedef struct _GstDroidCodec GstDroidCodec;
+typedef struct _GstDroidCamSrcPad GstDroidCamSrcPad;
+
+struct _GstDroidCamSrcRecorder
+{
+ /* opaque */
+
+ GstDroidCamSrcPad *vidsrc;
+ GstDroidCodec *codec;
+ DroidMediaRecorder *recorder;
+ DroidMediaCodecEncoderMetaData md;
+};
+
+GstDroidCamSrcRecorder *gst_droidcamsrc_recorder_create (GstDroidCamSrcPad *vidsrc);
+void gst_droidcamsrc_recorder_destroy (GstDroidCamSrcRecorder *recorder);
+
+gboolean gst_droidcamsrc_recorder_init (GstDroidCamSrcRecorder *recorder, DroidMediaCamera *cam, gint32 target_bitrate);
+
+void gst_droidcamsrc_recorder_update_vid (GstDroidCamSrcRecorder *recorder, GstVideoInfo *info, GstCaps *caps);
+
+gboolean gst_droidcamsrc_recorder_start (GstDroidCamSrcRecorder *recorder);
+void gst_droidcamsrc_recorder_stop (GstDroidCamSrcRecorder *recorder);
+
+G_END_DECLS
+
+#endif /* __GST_DROIDCAMSRC_RECORDER_H__ */
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcodec/Makefile.am
^
|
@@ -10,13 +10,11 @@
libgstdroidcodec_la_SOURCES = \
gstdroidvdec.c \
gstdroidvenc.c \
- gstdroidcodec.c \
gstdroidadec.c \
gstdroidaenc.c
noinst_HEADERS = \
gstdroidvdec.h \
gstdroidvenc.h \
- gstdroidcodec.h \
gstdroidadec.h \
gstdroidaenc.h
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcodec/gstdroidadec.h
^
|
@@ -25,7 +25,7 @@
#include <gst/gst.h>
#include <gst/audio/gstaudiodecoder.h>
#include <gst/base/gstadapter.h>
-#include "gstdroidcodec.h"
+#include "gst/droid/gstdroidcodec.h"
G_BEGIN_DECLS
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcodec/gstdroidaenc.h
^
|
@@ -23,7 +23,7 @@
#include <gst/gst.h>
#include <gst/audio/gstaudioencoder.h>
-#include "gstdroidcodec.h"
+#include "gst/droid/gstdroidcodec.h"
G_BEGIN_DECLS
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcodec/gstdroidvdec.c
^
|
@@ -215,6 +215,39 @@
GST_FIXME ("Not sure what to do here really");
}
+static void
+gst_droidvec_copy_plane (guint8 * out, gint stride_out, guint8 * in,
+ gint stride_in, gint width, gint height)
+{
+ int i;
+ for (i = 0; i < height; i++) {
+ orc_memcpy (out, in, width);
+ out += stride_out;
+ in += stride_in;
+ }
+}
+
+static void
+gst_droidvec_copy_packed_planes (guint8 * out0, guint8 * out1, gint stride_out,
+ guint8 * in, gint stride_in, gint width, gint height)
+{
+ int x, y;
+ for (y = 0; y < height; y++) {
+ guint8 *row = in;
+ for (x = 0; x < width; x++) {
+ out0[x] = row[0];
+ out1[x] = row[1];
+ row += 2;
+ }
+
+ out0 += stride_out;
+ out1 += stride_out;
+ in += stride_in;
+ }
+}
+
+#define ALIGN_SIZE(size, to) (((size) + to - 1) & ~(to - 1))
+
static gboolean
gst_droidvdec_convert_buffer (GstDroidVDec * dec,
GstBuffer * out, DroidMediaData * in, GstVideoInfo * info)
@@ -222,8 +255,7 @@
gsize height = info->height;
gsize width = info->width;
gsize size;
- gboolean use_external_buffer;
- guint8 *data = NULL;
+ gboolean use_droid_convert;
gboolean ret;
GstMapInfo map_info;
@@ -240,7 +272,7 @@
}
size = width * height * 3 / 2;
- use_external_buffer = gst_buffer_get_size (out) != size;
+ use_droid_convert = dec->convert && gst_buffer_get_size (out) == size;
map_info.data = NULL;
if (!gst_buffer_map (out, &map_info, GST_MAP_WRITE)) {
@@ -249,61 +281,35 @@
goto out;
}
- if (use_external_buffer) {
- GST_DEBUG_OBJECT (dec, "using an external buffer for I420 conversion.");
- data = g_malloc (size);
- } else {
- data = map_info.data;
- }
+ if (use_droid_convert) {
+ if (droid_media_convert_to_i420 (dec->convert, in, map_info.data) != true) {
+ GST_ELEMENT_ERROR (dec, LIBRARY, FAILED, (NULL),
+ ("failed to convert frame"));
- if (droid_media_convert_to_i420 (dec->convert, in, data) != true) {
- GST_ELEMENT_ERROR (dec, LIBRARY, FAILED, (NULL),
- ("failed to convert frame"));
-
- ret = FALSE;
- goto out;
- }
-
- if (use_external_buffer) {
- /* fix up the buffer */
- /* Code is based on gst-colorconv qcom backend */
-
- gint stride = GST_VIDEO_INFO_COMP_STRIDE (info, 0);
- gint strideUV = GST_VIDEO_INFO_COMP_STRIDE (info, 1);
- guint8 *p = data;
- guint8 *dst = map_info.data;
- int i;
- int x;
-
- /* Y */
- for (i = 0; i < info->height; i++) {
- orc_memcpy (dst, p, info->width);
- dst += stride;
- p += width;
- }
-
- /* NOP if height == info->height */
- p += (height - info->height) * width;
- /* U and V */
- for (x = 0; x < 2; x++) {
- for (i = 0; i < info->height / 2; i++) {
- orc_memcpy (dst, p, info->width / 2);
- dst += strideUV;
- p += width / 2;
- }
-
- /* NOP if height == info->height */
- p += (height - info->height) / 2 * width / 2;
+ ret = FALSE;
+ goto out;
}
+ } else {
+ /* copy to the output buffer swapping the u and v planes and cropping if necessary */
+ /* this assumes a NV12 format with 128 byte alignment */
+ gint stride = ALIGN_SIZE (width, 128);
+ gint slice_height = ALIGN_SIZE (height, 32);
+ gint top = ALIGN_SIZE (dec->crop_rect.top, 2);
+ gint left = ALIGN_SIZE (dec->crop_rect.left, 2);
+
+ guint8 *y = in->data + (top * stride) + left;
+ guint8 *uv = in->data + (stride * slice_height) + (top * stride / 2) + left;
+
+ gst_droidvec_copy_plane (map_info.data + info->offset[0], info->stride[0],
+ y, stride, info->width, info->height);
+ gst_droidvec_copy_packed_planes (map_info.data + info->offset[1],
+ map_info.data + info->offset[2], info->stride[1], uv, stride,
+ info->width / 2, info->height / 2);
}
ret = TRUE;
out:
- if (use_external_buffer && data) {
- g_free (data);
- }
-
if (map_info.data) {
gst_buffer_unmap (out, &map_info);
}
@@ -653,14 +659,11 @@
dec->convert = droid_media_convert_create ();
}
- if (!dec->convert) {
- GST_ELEMENT_ERROR (dec, LIBRARY, INIT, (NULL),
- ("Failed to create I420 converter"));
- goto error;
+ if (dec->convert) {
+ droid_media_convert_set_crop_rect (dec->convert, rect, md.width,
+ md.height);
+ GST_INFO_OBJECT (dec, "using I420 conversion for output buffers");
}
-
- droid_media_convert_set_crop_rect (dec->convert, rect, md.width, md.height);
- GST_INFO_OBJECT (dec, "using I420 conversion for output buffers");
}
if (!gst_video_decoder_negotiate (decoder)) {
@@ -1018,9 +1021,8 @@
* which breaks timestamping.
*/
data.ts =
- GST_CLOCK_TIME_IS_VALID (frame->
- pts) ? GST_TIME_AS_USECONDS (frame->pts) : GST_TIME_AS_USECONDS (frame->
- dts);
+ GST_CLOCK_TIME_IS_VALID (frame->pts) ? GST_TIME_AS_USECONDS (frame->
+ pts) : GST_TIME_AS_USECONDS (frame->dts);
data.sync = GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame) ? true : false;
/* This can deadlock if droidmedia/stagefright input buffer queue is full thus we
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcodec/gstdroidvdec.h
^
|
@@ -24,7 +24,7 @@
#include <gst/gst.h>
#include <gst/video/gstvideodecoder.h>
-#include "gstdroidcodec.h"
+#include "gst/droid/gstdroidcodec.h"
#include "droidmediaconvert.h"
G_BEGIN_DECLS
|
[-]
[+]
|
Changed |
_service:tar_git:gstreamer1.0-droid-0.20170918.0.tar.gz/gst/droidcodec/gstdroidvenc.h
^
|
@@ -23,7 +23,7 @@
#include <gst/gst.h>
#include <gst/video/gstvideoencoder.h>
-#include "gstdroidcodec.h"
+#include "gst/droid/gstdroidcodec.h"
G_BEGIN_DECLS
|