td_h264dec.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * Copyright (C) 2009-2010 Felipe Contreras
  3. * Copyright (C) 2008-2010 Nokia Corporation
  4. *
  5. * Authors:
  6. * Felipe Contreras <felipe.contreras@gmail.com>
  7. * Juha Alanen <juha.m.alanen@nokia.com>
  8. *
  9. * This file may be used under the terms of the GNU Lesser General Public
  10. * License version 2.1, a copy of which is found in LICENSE included in the
  11. * packaging of this file.
  12. */
  13. #include "dsp_bridge.h"
  14. #include "dmm_buffer.h"
  15. #include "gstdspbase.h"
  16. #include "gstdspvdec.h"
  17. #include "gstdspparse.h"
  18. struct create_args {
  19. uint32_t size;
  20. uint16_t num_streams;
  21. uint16_t in_id;
  22. uint16_t in_type;
  23. uint16_t in_count;
  24. uint16_t out_id;
  25. uint16_t out_type;
  26. uint16_t out_count;
  27. uint16_t reserved;
  28. uint32_t max_width;
  29. uint32_t max_height;
  30. uint32_t color_format;
  31. uint32_t max_framerate;
  32. uint32_t max_bitrate;
  33. uint32_t endianness;
  34. uint32_t profile;
  35. int32_t max_level;
  36. uint32_t mode;
  37. int32_t preroll;
  38. uint32_t stream_format;
  39. uint32_t display_width;
  40. };
  41. static void create_args(GstDspBase *base, unsigned *profile_id, void **arg_data)
  42. {
  43. GstDspVDec *self = GST_DSP_VDEC(base);
  44. struct create_args args = {
  45. .size = sizeof(args) - 4,
  46. .num_streams = 2,
  47. .in_id = 0,
  48. .in_type = 0,
  49. .in_count = base->ports[0]->num_buffers,
  50. .out_id = 1,
  51. .out_type = 0,
  52. .out_count = base->ports[1]->num_buffers,
  53. .max_width = self->width,
  54. .max_height = self->height,
  55. .color_format = self->color_format == GST_MAKE_FOURCC('U', 'Y', 'V', 'Y') ? 1 : 0,
  56. .max_bitrate = -1,
  57. .endianness = 1,
  58. .max_level = -1,
  59. };
  60. if (self->width * self->height > 352 * 288)
  61. *profile_id = 3;
  62. else if (self->width * self->height > 176 * 144)
  63. *profile_id = 2;
  64. else
  65. *profile_id = 1;
  66. *arg_data = malloc(sizeof(args));
  67. memcpy(*arg_data, &args, sizeof(args));
  68. }
  69. static void check_stream_params(GstDspBase *self, GstBuffer *buf)
  70. {
  71. GstDspVDec *vdec = GST_DSP_VDEC(self);
  72. /* Use a fake vdec to get width and height (if any) */
  73. GstDspVDec helper = *vdec;
  74. GstCaps *new_caps = gst_caps_copy(GST_PAD_CAPS(self->sinkpad));
  75. (GST_DSP_BASE(&helper))->tmp_caps = new_caps;
  76. if (vdec->width != 0 && vdec->height != 0 &&
  77. gst_dsp_h264_parse(GST_DSP_BASE(&helper), buf))
  78. {
  79. if (helper.width != vdec->width ||
  80. helper.height != vdec->height)
  81. {
  82. /* generate new caps */
  83. pr_debug(self, "frame size changed from %dx%d to %dx%d\n",
  84. vdec->width,
  85. vdec->height,
  86. helper.width,
  87. helper.height);
  88. gst_caps_set_simple(new_caps,
  89. "width", G_TYPE_INT, helper.width,
  90. "height", G_TYPE_INT, helper.height, NULL);
  91. gst_pad_set_caps(self->sinkpad, new_caps);
  92. }
  93. }
  94. gst_caps_unref(new_caps);
  95. }
  96. static GstBuffer *transform_codec_data(GstDspVDec *self, GstBuffer *buf)
  97. {
  98. guint8 *data, *outdata;
  99. guint size, total_size = 0, len, num_sps, num_pps;
  100. guint lol;
  101. guint val;
  102. guint i;
  103. GstBuffer *new;
  104. /* extract some info and transform into codec expected format, which is:
  105. * lol bytes (BE) SPS size, SPS, lol bytes (BE) PPS size, PPS */
  106. data = GST_BUFFER_DATA(buf);
  107. size = GST_BUFFER_SIZE(buf);
  108. if (size < 8)
  109. goto fail;
  110. val = GST_READ_UINT32_BE(data);
  111. if (val == 1 || (val >> 8) == 1) {
  112. pr_debug(self, "codec_data in byte-stream format not transformed");
  113. return gst_buffer_ref(buf);
  114. }
  115. lol = (data[4] & (0x3)) + 1;
  116. num_sps = data[5] & 0x1f;
  117. data += 6;
  118. size -= 6;
  119. for (i = 0; i < num_sps; i++) {
  120. len = GST_READ_UINT16_BE(data);
  121. total_size += len + lol;
  122. data += len + 2;
  123. if (size < len + 2)
  124. goto fail;
  125. size -= len + 2;
  126. }
  127. num_pps = data[0];
  128. data++;
  129. size++;
  130. for (i = 0; i < num_pps; i++) {
  131. len = GST_READ_UINT16_BE(data);
  132. total_size += len + lol;
  133. data += len + 2;
  134. if (size < len + 2)
  135. goto fail;
  136. size -= len + 2;
  137. }
  138. /* save original data */
  139. new = gst_buffer_new_and_alloc(total_size);
  140. data = GST_BUFFER_DATA(buf);
  141. outdata = GST_BUFFER_DATA(new);
  142. data += 6;
  143. for (i = 0; i < num_sps; ++i) {
  144. len = GST_READ_UINT16_BE(data);
  145. val = len << (8 * (4 - lol));
  146. GST_WRITE_UINT32_BE(outdata, val);
  147. memcpy(outdata + lol, data + 2, len);
  148. outdata += len + lol;
  149. data += 2 + len;
  150. }
  151. data += 1;
  152. for (i = 0; i < num_pps; ++i) {
  153. len = GST_READ_UINT16_BE(data);
  154. val = len << (8 * (4 - lol));
  155. GST_WRITE_UINT32_BE(outdata, val);
  156. memcpy(outdata + lol, data + 2, len);
  157. outdata += len + lol;
  158. data += 2 + len;
  159. }
  160. pr_debug(self, "lol: %d", lol);
  161. self->priv.h264.lol = lol;
  162. return new;
  163. fail:
  164. pr_warning(self, "failed to transform h264 to codec format");
  165. return NULL;
  166. }
  167. static void transform_nal_encoding(GstDspVDec *self, struct td_buffer *tb)
  168. {
  169. guint8 *data;
  170. gint size;
  171. gint lol;
  172. guint val, nal;
  173. dmm_buffer_t *b = tb->data;
  174. data = b->data;
  175. size = b->len;
  176. lol = self->priv.h264.lol;
  177. nal = 0;
  178. while (size) {
  179. if (size < lol)
  180. goto fail;
  181. /* get NAL size encoded in BE lol bytes */
  182. val = GST_READ_UINT32_BE(data);
  183. val >>= ((4 - lol) << 3);
  184. if (lol == 4)
  185. /* blank size prefix with 00 00 00 01 */
  186. GST_WRITE_UINT32_BE(data, 0x01);
  187. else if (lol == 3)
  188. /* blank size prefix with 00 00 01 */
  189. GST_WRITE_UINT24_BE(data, 0x01);
  190. else
  191. nal++;
  192. data += lol + val;
  193. size -= lol + val;
  194. }
  195. if (lol < 3) {
  196. /* slower, but unlikely path; need to copy stuff to make room for sync */
  197. guint8 *odata, *alloc_data;
  198. gint osize;
  199. /* set up for next run */
  200. data = b->data;
  201. size = b->len;
  202. osize = size + nal * (4 - lol);
  203. /* save this so it is not free'd by subsequent allocate */
  204. alloc_data = b->allocated_data;
  205. b->allocated_data = NULL;
  206. dmm_buffer_allocate(b, osize);
  207. odata = b->data;
  208. while (size) {
  209. if (size < lol)
  210. goto fail;
  211. /* get NAL size encoded in BE lol bytes */
  212. val = GST_READ_UINT32_BE(data);
  213. val >>= ((4 - lol) << 3);
  214. GST_WRITE_UINT32_BE(odata, 0x01);
  215. odata += 4;
  216. data += lol;
  217. memcpy(odata, data, val);
  218. odata += val;
  219. data += val;
  220. size -= lol + val;
  221. }
  222. /* now release original data */
  223. if (tb->user_data) {
  224. gst_buffer_unref(tb->user_data);
  225. tb->user_data = NULL;
  226. }
  227. free(alloc_data);
  228. }
  229. return;
  230. fail:
  231. pr_warning(self, "failed to transform h264 to codec format");
  232. return;
  233. }
  234. struct out_params {
  235. uint32_t display_id;
  236. uint32_t bytes_consumed;
  237. int32_t error_code;
  238. uint32_t frame_type;
  239. uint32_t num_of_nalu;
  240. int32_t mb_err_status_flag;
  241. int8_t mb_err_status_out[1620];
  242. };
  243. static void out_recv_cb(GstDspBase *base, struct td_buffer *tb)
  244. {
  245. GstDspVDec *vdec = GST_DSP_VDEC(base);
  246. dmm_buffer_t *b = tb->data;
  247. struct out_params *param;
  248. param = tb->params->data;
  249. pr_debug(base, "receive %zu/%ld",
  250. b->len, base->output_buffer_size);
  251. pr_debug(base, "error: 0x%x, frame type: %d",
  252. param->error_code, param->frame_type);
  253. if (param->error_code & 0xffff)
  254. pr_err(base, "decode error");
  255. gstdsp_vdec_len_fixup(vdec, b);
  256. }
  257. static void in_send_cb(GstDspBase *base, struct td_buffer *tb)
  258. {
  259. GstDspVDec *vdec = GST_DSP_VDEC(base);
  260. /* transform MP4 format to bytestream format */
  261. if (G_LIKELY(vdec->priv.h264.lol)) {
  262. pr_debug(base, "transforming H264 buffer data");
  263. /* intercept and transform into dsp expected format */
  264. transform_nal_encoding(vdec, tb);
  265. } else {
  266. /* no more need for callback */
  267. tb->port->send_cb = NULL;
  268. }
  269. }
  270. static void setup_params(GstDspBase *base)
  271. {
  272. struct out_params *out_param;
  273. du_port_t *p;
  274. p = base->ports[0];
  275. p->send_cb = in_send_cb;
  276. base->pre_process_buffer = check_stream_params;
  277. p = base->ports[1];
  278. gstdsp_port_setup_params(base, p, sizeof(*out_param), NULL);
  279. p->recv_cb = out_recv_cb;
  280. }
  281. static bool handle_extra_data(GstDspBase *base, GstBuffer *buf)
  282. {
  283. bool res;
  284. GstDspVDec *self = GST_DSP_VDEC(base);
  285. buf = transform_codec_data(self, buf);
  286. if (!buf) {
  287. gstdsp_got_error(base, 0, "invalid codec_data");
  288. return false;
  289. }
  290. res = gstdsp_send_codec_data(base, buf);
  291. gst_buffer_unref(buf);
  292. return res;
  293. }
  294. struct td_codec td_h264dec_codec = {
  295. .uuid = &(const struct dsp_uuid) { 0xCB1E9F0F, 0x9D5A, 0x4434, 0x84, 0x49,
  296. { 0x1F, 0xED, 0x2F, 0x99, 0x2D, 0xF7 } },
  297. .filename = "h264vdec_sn.dll64P",
  298. .setup_params = setup_params,
  299. .create_args = create_args,
  300. .handle_extra_data = handle_extra_data,
  301. };