2 * Copyright (C) 2003 Rik Snel <snel@phys.uu.nl>, license GPL v2
3 * - based on vd_mpegpes.c by A'rpi (C) 2002-2003
4 * - guess_mjpeg_type code stolen from lav_io.c (C) 2000 Rainer Johanni
5 * <Rainer@Johanni.de> from the mjpegtools package
13 /* some convenient #define's, is this portable enough? */
14 #define VERBOSE(...) mp_msg(MSGT_DECVIDEO, MSGL_V, "vd_zrmjpeg: " __VA_ARGS__)
15 #define ERROR(...) mp_msg(MSGT_DECVIDEO, MSGL_ERR, "vd_zrmjpeg: " __VA_ARGS__)
16 #define WARNING(...) mp_msg(MSGT_DECVIDEO, MSGL_WARN, \
17 "vd_zrmjpeg: " __VA_ARGS__)
19 #include "vd_internal.h"
21 static vd_info_t info
=
23 "Zoran MJPEG Video passthrough",
25 "Rik Snel <snel@phys.uu.nl>",
26 "Rik Snel <snel@phys.uu.nl>",
27 "for hw decoders (DC10(+)/buz/lml33)"
32 #include "libvo/video_out.h"
36 unsigned int preferred_csp
;
39 static int query_format(sh_video_t
*sh
, unsigned int format
) {
40 vd_zrmjpeg_ctx_t
*ctx
= sh
->context
;
41 if (format
== ctx
->preferred_csp
) return CONTROL_TRUE
;
45 // to set/get/query special features/parameters
46 static int control(sh_video_t
*sh
, int cmd
, void* arg
, ...) {
48 case VDCTRL_QUERY_FORMAT
:
49 return query_format(sh
, *((unsigned int*)arg
));
51 return CONTROL_UNKNOWN
;
55 static int init(sh_video_t
*sh
) {
56 vd_zrmjpeg_ctx_t
*ctx
;
58 VERBOSE("init called\n");
59 ctx
= malloc(sizeof(*ctx
));
61 memset(ctx
, 0, sizeof(*ctx
));
64 /* defer init of vo until the first frame is known */
67 return mpcodecs_config_vo(sh
, sh
->disp_w
, sh
->disp_h
, IMGFMT_ZRMJPEGIT
);
72 static void uninit(sh_video_t
*sh
) {
76 /* parts directly stolen from scan_jpg() and lav_open_input_file */
77 static int get_int2(unsigned char *buf
) {
78 return buf
[0]*256 + buf
[1];
84 #define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
85 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
86 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
90 /* returns 0 in case of failure */
91 static unsigned int guess_mjpeg_type(unsigned char *data
, unsigned int size
,
94 int marker
, length
, height
, ncomps
, i
, hf
[3], vf
[3];
95 unsigned int app0
= 0, header
= 0;
97 /* The initial marker must be SIO */
99 ERROR("JPEG data too short (%d bytes)\n", size
);
103 if (data
[0] != 0xFF || data
[1] != M_SOI
) {
104 ERROR("JPEG data must start with FFD8, but doesn't\n");
108 p
= 2; /* pointer within jpeg data */
112 while(data
[p
] != 0xFF) {
114 if (p
>= size
) return 0;
117 /* get marker code, skip duplicate FF's */
118 while(data
[p
] == 0xFF) {
120 if (p
>= size
) return 0;
125 /* marker may have an associated length */
126 if (p
<= size
- 2) length
= get_int2(data
+p
);
133 VERBOSE("found offset of header %u\n",
141 VERBOSE("found offset of APP0 %u\n",
146 /* these markers shouldn't have parameters,
147 * i.e. we don't need to skip anaything */
148 if (marker
== 0 || marker
== 1 ||
149 (marker
>= 0xd0 && marker
< 0xd8))
152 if (p
+ length
<= size
) p
+= length
;
154 ERROR("input JPEG too short, data missing\n");
160 ERROR("JPEG header (with resolution and sampling factors) not found\n");
164 if (data
[header
+ 9] != 3) {
165 ERROR("JPEG has wrong number of components\n");
169 /* get the horizontal and vertical sample factors */
170 for (i
= 0; i
< 3; i
++) {
171 hf
[i
] = data
[header
+ 10 + 3*i
+ 1]>>4;
172 vf
[i
] = data
[header
+ 10 + 3*i
+ 1]&0x0F;
175 if (hf
[0] != 2 || hf
[1] != 1 || hf
[2] != 1 ||
176 vf
[0] != 1 || vf
[1] != 1 || vf
[2] != 1) {
177 ERROR("JPEG has wrong internal image format\n");
178 } else VERBOSE("JPEG has colorspace YUV422 with minimal sampling factors (good)\n");
180 height
= get_int2(data
+ header
+ 5);
181 if (height
== d_height
) {
182 VERBOSE("data is non interlaced\n");
183 return IMGFMT_ZRMJPEGNI
;
186 if (2*height
!= d_height
) {
187 ERROR("something very inconsistent happened\n");
192 if (app0
&& get_int2(data
+ app0
+ 2) >= 5 &&
193 strncasecmp((char*)(data
+ app0
+ 4), "AVI1", 4) == 0) {
194 if (data
[app0
+8] == 1) {
195 VERBOSE("data is interlaced, APP0: top-first (1)\n");
196 return IMGFMT_ZRMJPEGIT
;
198 VERBOSE("data is interlaced, APP0: bottom-first (%d)\n",
200 return IMGFMT_ZRMJPEGIB
;
203 VERBOSE("data is interlaced, no (valid) APP0 marker, "
204 "guessing top-first\n");
205 return IMGFMT_ZRMJPEGIT
;
213 static mp_image_t
* decode(sh_video_t
*sh
, void* data
, int len
, int flags
) {
215 vd_zrmjpeg_ctx_t
*ctx
= sh
->context
;
217 if (!ctx
->vo_inited
) {
218 ctx
->preferred_csp
= guess_mjpeg_type(data
, len
, sh
->disp_h
);
219 if (ctx
->preferred_csp
== 0) return NULL
;
220 mpcodecs_config_vo(sh
, sh
->disp_w
, sh
->disp_h
,
225 mpi
= mpcodecs_get_image(sh
, MP_IMGTYPE_EXPORT
, 0,
226 sh
->disp_w
, sh
->disp_h
);
228 mpi
->planes
[0]=(uint8_t*)data
;
229 mpi
->planes
[1]=(uint8_t*)len
;