GNU Linux-libre 4.14.295-gnu1
[releases.git] / drivers / media / platform / coda / coda-h264.c
1 /*
2  * Coda multi-standard codec IP - H.264 helper functions
3  *
4  * Copyright (C) 2012 Vista Silicon S.L.
5  *    Javier Martin, <javier.martin@vista-silicon.com>
6  *    Xavier Duret
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/string.h>
16 #include <linux/videodev2.h>
17 #include <coda.h>
18
19 static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
20
21 static const u8 *coda_find_nal_header(const u8 *buf, const u8 *end)
22 {
23         u32 val = 0xffffffff;
24
25         do {
26                 val = val << 8 | *buf++;
27                 if (buf >= end)
28                         return NULL;
29         } while (val != 0x00000001);
30
31         return buf;
32 }
33
34 int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb)
35 {
36         const u8 *buf = vb2_plane_vaddr(vb, 0);
37         const u8 *end = buf + vb2_get_plane_payload(vb, 0);
38
39         /* Find SPS header */
40         do {
41                 buf = coda_find_nal_header(buf, end);
42                 if (!buf)
43                         return -EINVAL;
44         } while ((*buf++ & 0x1f) != 0x7);
45
46         ctx->params.h264_profile_idc = buf[0];
47         ctx->params.h264_level_idc = buf[2];
48
49         return 0;
50 }
51
52 int coda_h264_filler_nal(int size, char *p)
53 {
54         if (size < 6)
55                 return -EINVAL;
56
57         p[0] = 0x00;
58         p[1] = 0x00;
59         p[2] = 0x00;
60         p[3] = 0x01;
61         p[4] = 0x0c;
62         memset(p + 5, 0xff, size - 6);
63         /* Add rbsp stop bit and trailing at the end */
64         p[size - 1] = 0x80;
65
66         return 0;
67 }
68
69 int coda_h264_padding(int size, char *p)
70 {
71         int nal_size;
72         int diff;
73
74         diff = size - (size & ~0x7);
75         if (diff == 0)
76                 return 0;
77
78         nal_size = coda_filler_size[diff];
79         coda_h264_filler_nal(nal_size, p);
80
81         return nal_size;
82 }
83
84 int coda_h264_profile(int profile_idc)
85 {
86         switch (profile_idc) {
87         case 66: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
88         case 77: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
89         case 88: return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
90         case 100: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
91         default: return -EINVAL;
92         }
93 }
94
95 int coda_h264_level(int level_idc)
96 {
97         switch (level_idc) {
98         case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
99         case 9:  return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
100         case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
101         case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
102         case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
103         case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
104         case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
105         case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
106         case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
107         case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
108         case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
109         case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
110         case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
111         default: return -EINVAL;
112         }
113 }