gstdspvdec.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*
  2. * Copyright (C) 2009-2010 Felipe Contreras
  3. *
  4. * Authors:
  5. * Felipe Contreras <felipe.contreras@gmail.com>
  6. * Juha Alanen <juha.m.alanen@nokia.com>
  7. *
  8. * This file may be used under the terms of the GNU Lesser General Public
  9. * License version 2.1, a copy of which is found in LICENSE included in the
  10. * packaging of this file.
  11. */
  12. #include "gstdspvdec.h"
  13. #include "gstdspparse.h"
  14. #include "plugin.h"
  15. #include "util.h"
  16. #include "dsp_bridge.h"
  17. #include <string.h> /* for memcpy */
  18. #include "log.h"
  19. #define GST_CAT_DEFAULT gstdsp_debug
  20. static GstDspBaseClass *parent_class;
  21. static inline GstCaps *
  22. generate_sink_template(void)
  23. {
  24. GstCaps *caps;
  25. GstStructure *struc;
  26. caps = gst_caps_new_empty();
  27. struc = gst_structure_new("video/mpeg",
  28. "mpegversion", G_TYPE_INT, 4,
  29. "systemstream", G_TYPE_BOOLEAN, FALSE,
  30. NULL);
  31. gst_caps_append_structure(caps, struc);
  32. struc = gst_structure_new("video/x-divx",
  33. "divxversion", GST_TYPE_INT_RANGE, 4, 5,
  34. NULL);
  35. gst_caps_append_structure(caps, struc);
  36. struc = gst_structure_new("video/x-xvid",
  37. NULL);
  38. gst_caps_append_structure(caps, struc);
  39. struc = gst_structure_new("video/x-3ivx",
  40. NULL);
  41. gst_caps_append_structure(caps, struc);
  42. struc = gst_structure_new("video/x-h263",
  43. "variant", G_TYPE_STRING, "itu",
  44. NULL);
  45. gst_caps_append_structure(caps, struc);
  46. struc = gst_structure_new("video/x-h264", "alignment", G_TYPE_STRING, "au",
  47. NULL);
  48. gst_caps_append_structure(caps, struc);
  49. struc = gst_structure_new("video/x-wmv",
  50. "wmvversion", G_TYPE_INT, 3,
  51. NULL);
  52. gst_caps_append_structure(caps, struc);
  53. struc = gst_structure_new("image/jpeg",
  54. "parsed", G_TYPE_BOOLEAN, TRUE,
  55. NULL);
  56. gst_caps_append_structure(caps, struc);
  57. return caps;
  58. }
  59. static inline GstCaps *
  60. generate_src_template(void)
  61. {
  62. GstCaps *caps;
  63. GstStructure *struc;
  64. caps = gst_caps_new_empty();
  65. struc = gst_structure_new("video/x-raw-yuv",
  66. "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'),
  67. NULL);
  68. gst_caps_append_structure(caps, struc);
  69. struc = gst_structure_new("video/x-raw-yuv",
  70. "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('I', '4', '2', '0'),
  71. NULL);
  72. gst_caps_append_structure(caps, struc);
  73. return caps;
  74. }
  75. void gstdsp_vdec_len_fixup(GstDspVDec *self, dmm_buffer_t *b)
  76. {
  77. /* let the videosink know the real size */
  78. if (self->color_format == GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'))
  79. b->len = self->crop_width * self->crop_height * 2;
  80. else
  81. b->len = self->crop_width * self->crop_height * 3 / 2;
  82. }
  83. static void *
  84. create_node(GstDspBase *base)
  85. {
  86. GstDspVDec *self;
  87. struct td_codec *codec;
  88. int dsp_handle;
  89. struct dsp_node *node;
  90. const struct dsp_uuid usn_uuid = { 0x79A3C8B3, 0x95F2, 0x403F, 0x9A, 0x4B,
  91. { 0xCF, 0x80, 0x57, 0x73, 0x05, 0x41 } };
  92. const struct dsp_uuid ringio_uuid = { 0x47698bfb, 0xa7ee, 0x417e, 0xa6, 0x7a,
  93. { 0x41, 0xc0, 0x27, 0x9e, 0xb8, 0x05 } };
  94. const struct dsp_uuid conversions_uuid = { 0x722DD0DA, 0xF532, 0x4238, 0xB8, 0x46,
  95. { 0xAB, 0xFF, 0x5D, 0xA4, 0xBA, 0x02 } };
  96. self = GST_DSP_VDEC(base);
  97. dsp_handle = base->dsp_handle;
  98. if (!gstdsp_register(dsp_handle, &ringio_uuid, DSP_DCD_LIBRARYTYPE, "ringio.dll64P")) {
  99. pr_err(self, "failed to register ringio node library");
  100. return NULL;
  101. }
  102. if (!gstdsp_register(dsp_handle, &usn_uuid, DSP_DCD_LIBRARYTYPE, "usn.dll64P")) {
  103. pr_err(self, "failed to register usn node library");
  104. return NULL;
  105. }
  106. codec = base->codec;
  107. if (!codec) {
  108. pr_err(self, "unknown algorithm");
  109. return NULL;
  110. }
  111. pr_info(base, "algo=%s", codec->filename);
  112. /* SN_API == 0 doesn't have it, so don't fail */
  113. (void) gstdsp_register(dsp_handle, &conversions_uuid, DSP_DCD_LIBRARYTYPE, "conversions.dll64P");
  114. if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_LIBRARYTYPE, codec->filename)) {
  115. pr_err(self, "failed to register algo node library");
  116. return NULL;
  117. }
  118. if (!gstdsp_register(dsp_handle, codec->uuid, DSP_DCD_NODETYPE, codec->filename)) {
  119. pr_err(self, "failed to register algo node");
  120. return NULL;
  121. }
  122. {
  123. struct dsp_node_attr_in attrs = {
  124. .cb = sizeof(attrs),
  125. .priority = 5,
  126. .timeout = 1000,
  127. };
  128. void *arg_data;
  129. codec->create_args(base, &attrs.profile_id, &arg_data);
  130. if (!arg_data)
  131. return NULL;
  132. if (!dsp_node_allocate(dsp_handle, base->proc, codec->uuid, arg_data, &attrs, &node)) {
  133. pr_err(self, "dsp node allocate failed");
  134. free(arg_data);
  135. return NULL;
  136. }
  137. free(arg_data);
  138. }
  139. if (!dsp_node_create(dsp_handle, node)) {
  140. pr_err(self, "dsp node create failed");
  141. dsp_node_free(dsp_handle, node);
  142. return NULL;
  143. }
  144. pr_info(self, "dsp node created");
  145. if (codec->setup_params)
  146. codec->setup_params(base);
  147. if (codec->send_params)
  148. codec->send_params(base, node);
  149. base->flush_buffer = codec->flush_buffer;
  150. return node;
  151. }
  152. static void save_codec_data(GstDspBase *base, GstStructure *in_struc)
  153. {
  154. const GValue *codec_data;
  155. GstBuffer *buf;
  156. codec_data = gst_structure_get_value(in_struc, "codec_data");
  157. if (!codec_data)
  158. return;
  159. buf = gst_value_get_buffer(codec_data);
  160. if (!buf)
  161. return;
  162. gst_buffer_unref(base->codec_data);
  163. base->codec_data = gst_buffer_ref(buf);
  164. }
  165. static inline void
  166. configure_caps(GstDspVDec *self,
  167. GstCaps *in,
  168. GstCaps *out)
  169. {
  170. GstDspBase *base;
  171. GstCaps *allowed_caps;
  172. GstStructure *out_struc, *in_struc;
  173. const GValue *aspect_ratio;
  174. bool i420_is_valid = true;
  175. base = GST_DSP_BASE(self);
  176. in_struc = gst_caps_get_structure(in, 0);
  177. out_struc = gst_structure_new("video/x-raw-yuv",
  178. "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'),
  179. NULL);
  180. gst_structure_get_int(in_struc, "width", &self->width);
  181. gst_structure_get_int(in_struc, "height", &self->height);
  182. self->crop_width = self->width;
  183. self->crop_height = self->height;
  184. gst_structure_set(out_struc, "width", G_TYPE_INT, self->crop_width, NULL);
  185. gst_structure_set(out_struc, "height", G_TYPE_INT, self->crop_height, NULL);
  186. aspect_ratio = gst_structure_get_value(in_struc, "pixel-aspect-ratio");
  187. if (aspect_ratio)
  188. gst_structure_set_value(out_struc, "pixel-aspect-ratio", aspect_ratio);
  189. /* estimate the real coded framesize */
  190. self->width = ROUND_UP(self->width, 16);
  191. self->height = ROUND_UP(self->height, 16);
  192. base->output_buffer_size = self->width * self->height * 2;
  193. self->color_format = GST_MAKE_FOURCC('U', 'Y', 'V', 'Y');
  194. /* in jpegdec I420 is only possible if the image has that chroma */
  195. if (base->alg == GSTDSP_JPEGDEC) {
  196. guint32 color_format;
  197. if (gst_structure_get_fourcc(in_struc, "format", &color_format))
  198. i420_is_valid = (color_format == GST_MAKE_FOURCC('I', '4', '2', '0'));
  199. else
  200. i420_is_valid = false; /* we don't know the chroma */
  201. }
  202. allowed_caps = gst_pad_get_allowed_caps(base->srcpad);
  203. if (allowed_caps) {
  204. if (gst_caps_get_size(allowed_caps) > 0) {
  205. GstStructure *s;
  206. guint32 color_format;
  207. s = gst_caps_get_structure(allowed_caps, 0);
  208. if (gst_structure_get_fourcc(s, "format", &color_format)) {
  209. if (color_format == GST_MAKE_FOURCC('I', '4', '2', '0')
  210. && i420_is_valid) {
  211. self->color_format = color_format;
  212. base->output_buffer_size = self->width * self->height * 3 / 2;
  213. gst_structure_set(out_struc, "format", GST_TYPE_FOURCC,
  214. GST_MAKE_FOURCC('I', '4', '2', '0'), NULL);
  215. }
  216. }
  217. }
  218. gst_caps_unref(allowed_caps);
  219. }
  220. {
  221. const GValue *framerate = NULL;
  222. framerate = gst_structure_get_value(in_struc, "framerate");
  223. if (framerate)
  224. gst_structure_set_value(out_struc, "framerate", framerate);
  225. else
  226. /* FIXME this is a workaround for xvimagesink */
  227. gst_structure_set(out_struc, "framerate",
  228. GST_TYPE_FRACTION, 0, 1, NULL);
  229. base->default_duration = 0;
  230. if (framerate) {
  231. guint fps_num = 0, fps_den = 0;
  232. fps_num = gst_value_get_fraction_numerator(framerate);
  233. fps_den = gst_value_get_fraction_denominator(framerate);
  234. if (fps_num && fps_den)
  235. base->default_duration = gst_util_uint64_scale(GST_SECOND, fps_den, fps_num);
  236. }
  237. }
  238. gst_caps_append_structure(out, out_struc);
  239. }
  240. static inline gboolean need_node_reset(GstDspVDec *self, GstCaps *new_caps)
  241. {
  242. gint width, height;
  243. GstStructure *struc;
  244. GstDspBase *base = GST_DSP_BASE(self);
  245. if (G_UNLIKELY(!base->node))
  246. return FALSE;
  247. struc = gst_caps_get_structure(new_caps, 0);
  248. gst_structure_get_int(struc, "width", &width);
  249. gst_structure_get_int(struc, "height", &height);
  250. if (self->width == width && self->height == height)
  251. return FALSE;
  252. return TRUE;
  253. }
  254. static gboolean
  255. sink_setcaps(GstPad *pad,
  256. GstCaps *caps)
  257. {
  258. GstDspVDec *self;
  259. GstDspBase *base;
  260. GstStructure *in_struc;
  261. GstCaps *out_caps;
  262. const char *name;
  263. gboolean ret;
  264. struct td_codec *codec;
  265. self = GST_DSP_VDEC(GST_PAD_PARENT(pad));
  266. base = GST_DSP_BASE(self);
  267. #ifdef DEBUG
  268. {
  269. gchar *str = gst_caps_to_string(caps);
  270. pr_info(self, "sink caps: %s", str);
  271. g_free(str);
  272. }
  273. #endif
  274. if (need_node_reset(self, caps))
  275. gstdsp_reinit(base);
  276. in_struc = gst_caps_get_structure(caps, 0);
  277. if (base->node)
  278. goto skip_setup;
  279. base->parsed = false;
  280. name = gst_structure_get_name(in_struc);
  281. if (strcmp(name, "video/x-h264") == 0) {
  282. base->alg = GSTDSP_H264DEC;
  283. self->priv.h264.lol = 0;
  284. base->parse_func = gst_dsp_h264_parse;
  285. }
  286. else if (strcmp(name, "video/x-h263") == 0) {
  287. base->alg = GSTDSP_H263DEC;
  288. base->parse_func = gst_dsp_h263_parse;
  289. }
  290. else if (strcmp(name, "video/x-wmv") == 0) {
  291. guint32 fourcc;
  292. base->alg = GSTDSP_WMVDEC;
  293. if (gst_structure_get_fourcc(in_struc, "fourcc", &fourcc) ||
  294. gst_structure_get_fourcc(in_struc, "format", &fourcc))
  295. {
  296. if (fourcc == GST_MAKE_FOURCC('W', 'V', 'C', '1'))
  297. self->wmv_is_vc1 = TRUE;
  298. else
  299. self->wmv_is_vc1 = FALSE;
  300. }
  301. }
  302. else if (strcmp(name, "image/jpeg") == 0) {
  303. base->alg = GSTDSP_JPEGDEC;
  304. gst_structure_get_boolean(in_struc, "interlaced",
  305. &self->jpeg_is_interlaced);
  306. }
  307. else {
  308. base->alg = GSTDSP_MPEG4VDEC;
  309. base->parse_func = gst_dsp_mpeg4_parse;
  310. }
  311. switch (base->alg) {
  312. case GSTDSP_MPEG4VDEC:
  313. case GSTDSP_H263DEC:
  314. codec = &td_mp4vdec_codec;
  315. break;
  316. case GSTDSP_H264DEC:
  317. codec = &td_h264dec_codec;
  318. break;
  319. case GSTDSP_WMVDEC:
  320. codec = &td_wmvdec_codec;
  321. break;
  322. case GSTDSP_JPEGDEC:
  323. codec = &td_jpegdec_codec;
  324. break;
  325. default:
  326. codec = NULL;
  327. break;
  328. }
  329. base->codec = codec;
  330. switch (base->alg) {
  331. case GSTDSP_JPEGDEC:
  332. du_port_alloc_buffers(base->ports[0], 1);
  333. du_port_alloc_buffers(base->ports[1], 1);
  334. break;
  335. default:
  336. du_port_alloc_buffers(base->ports[0], 2);
  337. du_port_alloc_buffers(base->ports[1], 2);
  338. break;
  339. }
  340. skip_setup:
  341. out_caps = gst_caps_new_empty();
  342. configure_caps(self, caps, out_caps);
  343. base->tmp_caps = out_caps;
  344. ret = gst_pad_set_caps(pad, caps);
  345. if (!ret)
  346. return FALSE;
  347. save_codec_data(base, in_struc);
  348. return TRUE;
  349. }
  350. static void
  351. instance_init(GTypeInstance *instance,
  352. gpointer g_class)
  353. {
  354. GstDspBase *base;
  355. base = GST_DSP_BASE(instance);
  356. base->use_pad_alloc = TRUE;
  357. base->create_node = create_node;
  358. gst_pad_set_setcaps_function(base->sinkpad, sink_setcaps);
  359. }
  360. static void
  361. base_init(gpointer g_class)
  362. {
  363. GstElementClass *element_class;
  364. GstPadTemplate *template;
  365. element_class = GST_ELEMENT_CLASS(g_class);
  366. gst_element_class_set_details_simple(element_class,
  367. "DSP video decoder",
  368. "Codec/Decoder/Video",
  369. "Decodes video with TI's DSP algorithms",
  370. "Felipe Contreras");
  371. template = gst_pad_template_new("src", GST_PAD_SRC,
  372. GST_PAD_ALWAYS,
  373. generate_src_template());
  374. gst_element_class_add_pad_template(element_class, template);
  375. gst_object_unref(template);
  376. template = gst_pad_template_new("sink", GST_PAD_SINK,
  377. GST_PAD_ALWAYS,
  378. generate_sink_template());
  379. gst_element_class_add_pad_template(element_class, template);
  380. gst_object_unref(template);
  381. }
  382. static void
  383. class_init(gpointer g_class,
  384. gpointer class_data)
  385. {
  386. parent_class = g_type_class_peek_parent(g_class);
  387. }
  388. GType
  389. gst_dsp_vdec_get_type(void)
  390. {
  391. static GType type;
  392. if (G_UNLIKELY(type == 0)) {
  393. GTypeInfo type_info = {
  394. .class_size = sizeof(GstDspVDecClass),
  395. .class_init = class_init,
  396. .base_init = base_init,
  397. .instance_size = sizeof(GstDspVDec),
  398. .instance_init = instance_init,
  399. };
  400. type = g_type_register_static(GST_DSP_BASE_TYPE, "GstDspVDec", &type_info, 0);
  401. }
  402. return type;
  403. }