/src/mpv/demux/demux_raw.c
Line | Count | Source |
1 | | /* |
2 | | * This file is part of mpv. |
3 | | * |
4 | | * mpv is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at your option) any later version. |
8 | | * |
9 | | * mpv is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | * GNU Lesser General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Lesser General Public |
15 | | * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | |
18 | | #include <stdlib.h> |
19 | | #include <stdio.h> |
20 | | #include <string.h> |
21 | | |
22 | | #include <libavcodec/avcodec.h> |
23 | | #include <libavutil/common.h> |
24 | | |
25 | | #include "common/av_common.h" |
26 | | |
27 | | #include "options/m_config.h" |
28 | | #include "options/m_option.h" |
29 | | |
30 | | #include "stream/stream.h" |
31 | | #include "demux.h" |
32 | | #include "stheader.h" |
33 | | #include "codec_tags.h" |
34 | | |
35 | | #include "video/fmt-conversion.h" |
36 | | #include "video/img_format.h" |
37 | | |
38 | | #include "osdep/endian.h" |
39 | | |
40 | | struct demux_rawaudio_opts { |
41 | | struct m_channels channels; |
42 | | int samplerate; |
43 | | int aformat; |
44 | | }; |
45 | | |
46 | | // Ad-hoc schema to systematically encode the format as int |
47 | | #define PCM(sign, is_float, bits, is_be) \ |
48 | | ((sign) | ((is_float) << 1) | ((is_be) << 2) | ((bits) << 3)) |
49 | | #define NE (BYTE_ORDER == BIG_ENDIAN) |
50 | | |
51 | | #define OPT_BASE_STRUCT struct demux_rawaudio_opts |
52 | | const struct m_sub_options demux_rawaudio_conf = { |
53 | | .opts = (const m_option_t[]) { |
54 | | {"channels", OPT_CHANNELS(channels), .flags = M_OPT_CHANNELS_LIMITED}, |
55 | | {"rate", OPT_INT(samplerate), M_RANGE(1000, 8 * 48000)}, |
56 | | {"format", OPT_CHOICE(aformat, |
57 | | {"u8", PCM(0, 0, 8, 0)}, |
58 | | {"s8", PCM(1, 0, 8, 0)}, |
59 | | {"u16le", PCM(0, 0, 16, 0)}, {"u16be", PCM(0, 0, 16, 1)}, |
60 | | {"s16le", PCM(1, 0, 16, 0)}, {"s16be", PCM(1, 0, 16, 1)}, |
61 | | {"u24le", PCM(0, 0, 24, 0)}, {"u24be", PCM(0, 0, 24, 1)}, |
62 | | {"s24le", PCM(1, 0, 24, 0)}, {"s24be", PCM(1, 0, 24, 1)}, |
63 | | {"u32le", PCM(0, 0, 32, 0)}, {"u32be", PCM(0, 0, 32, 1)}, |
64 | | {"s32le", PCM(1, 0, 32, 0)}, {"s32be", PCM(1, 0, 32, 1)}, |
65 | | {"floatle", PCM(0, 1, 32, 0)}, {"floatbe", PCM(0, 1, 32, 1)}, |
66 | | {"doublele",PCM(0, 1, 64, 0)}, {"doublebe", PCM(0, 1, 64, 1)}, |
67 | | {"u16", PCM(0, 0, 16, NE)}, |
68 | | {"s16", PCM(1, 0, 16, NE)}, |
69 | | {"u24", PCM(0, 0, 24, NE)}, |
70 | | {"s24", PCM(1, 0, 24, NE)}, |
71 | | {"u32", PCM(0, 0, 32, NE)}, |
72 | | {"s32", PCM(1, 0, 32, NE)}, |
73 | | {"float", PCM(0, 1, 32, NE)}, |
74 | | {"double", PCM(0, 1, 64, NE)})}, |
75 | | {0} |
76 | | }, |
77 | | .size = sizeof(struct demux_rawaudio_opts), |
78 | | .defaults = &(const struct demux_rawaudio_opts){ |
79 | | // Note that currently, stream_cdda expects exactly these parameters! |
80 | | .channels = { |
81 | | .set = 1, |
82 | | .chmaps = (struct mp_chmap[]){ MP_CHMAP_INIT_STEREO, }, |
83 | | .num_chmaps = 1, |
84 | | }, |
85 | | .samplerate = 44100, |
86 | | .aformat = PCM(1, 0, 16, 0), // s16le |
87 | | }, |
88 | | .change_flags = UPDATE_DEMUXER, |
89 | | }; |
90 | | |
91 | | #undef PCM |
92 | | #undef NE |
93 | | |
94 | | struct demux_rawvideo_opts { |
95 | | int vformat; |
96 | | int mp_format; |
97 | | char *codec; |
98 | | int width; |
99 | | int height; |
100 | | float fps; |
101 | | int imgsize; |
102 | | }; |
103 | | |
104 | | #undef OPT_BASE_STRUCT |
105 | | #define OPT_BASE_STRUCT struct demux_rawvideo_opts |
106 | | const struct m_sub_options demux_rawvideo_conf = { |
107 | | .opts = (const m_option_t[]) { |
108 | | {"w", OPT_INT(width), M_RANGE(1, 8192)}, |
109 | | {"h", OPT_INT(height), M_RANGE(1, 8192)}, |
110 | | {"format", OPT_FOURCC(vformat)}, |
111 | | {"mp-format", OPT_IMAGEFORMAT(mp_format)}, |
112 | | {"codec", OPT_STRING(codec)}, |
113 | | {"fps", OPT_FLOAT(fps), M_RANGE(0.001, 1000)}, |
114 | | {"size", OPT_INT(imgsize), M_RANGE(1, 8192 * 8192 * 4)}, |
115 | | {0} |
116 | | }, |
117 | | .size = sizeof(struct demux_rawvideo_opts), |
118 | | .defaults = &(const struct demux_rawvideo_opts){ |
119 | | .vformat = MKTAG('I', '4', '2', '0'), |
120 | | .width = 1280, |
121 | | .height = 720, |
122 | | .fps = 25, |
123 | | }, |
124 | | }; |
125 | | |
126 | | struct priv { |
127 | | struct sh_stream *sh; |
128 | | int frame_size; |
129 | | int read_frames; |
130 | | double frame_rate; |
131 | | }; |
132 | | |
133 | | static int generic_open(struct demuxer *demuxer) |
134 | 0 | { |
135 | 0 | struct stream *s = demuxer->stream; |
136 | 0 | struct priv *p = demuxer->priv; |
137 | |
|
138 | 0 | int64_t end = stream_get_size(s); |
139 | 0 | if (end >= 0) |
140 | 0 | demuxer->duration = (end / p->frame_size) / p->frame_rate; |
141 | |
|
142 | 0 | return 0; |
143 | 0 | } |
144 | | |
145 | | static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check) |
146 | 108k | { |
147 | 108k | struct demux_rawaudio_opts *opts = |
148 | 108k | mp_get_config_group(demuxer, demuxer->global, &demux_rawaudio_conf); |
149 | | |
150 | 108k | if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE) |
151 | 108k | return -1; |
152 | | |
153 | 0 | if (opts->channels.num_chmaps != 1) { |
154 | 0 | MP_ERR(demuxer, "Invalid channels option given.\n"); |
155 | 0 | return -1; |
156 | 0 | } |
157 | | |
158 | 0 | struct sh_stream *sh = demux_alloc_sh_stream(STREAM_AUDIO); |
159 | 0 | struct mp_codec_params *c = sh->codec; |
160 | 0 | c->channels = opts->channels.chmaps[0]; |
161 | 0 | c->force_channels = true; |
162 | 0 | c->samplerate = opts->samplerate; |
163 | |
|
164 | 0 | c->native_tb_num = 1; |
165 | 0 | c->native_tb_den = c->samplerate; |
166 | |
|
167 | 0 | int f = opts->aformat; |
168 | | // See PCM(): sign float bits endian |
169 | 0 | mp_set_pcm_codec(sh->codec, f & 1, f & 2, f >> 3, f & 4); |
170 | 0 | int samplesize = ((f >> 3) + 7) / 8; |
171 | |
|
172 | 0 | demux_add_sh_stream(demuxer, sh); |
173 | |
|
174 | 0 | struct priv *p = talloc_ptrtype(demuxer, p); |
175 | 0 | demuxer->priv = p; |
176 | 0 | *p = (struct priv) { |
177 | 0 | .sh = sh, |
178 | 0 | .frame_size = samplesize * c->channels.num, |
179 | 0 | .frame_rate = c->samplerate, |
180 | 0 | .read_frames = c->samplerate / 8, |
181 | 0 | }; |
182 | |
|
183 | 0 | return generic_open(demuxer); |
184 | 0 | } |
185 | | |
186 | | static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check) |
187 | 108k | { |
188 | 108k | struct demux_rawvideo_opts *opts = |
189 | 108k | mp_get_config_group(demuxer, demuxer->global, &demux_rawvideo_conf); |
190 | | |
191 | 108k | if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE) |
192 | 108k | return -1; |
193 | | |
194 | 0 | int width = opts->width; |
195 | 0 | int height = opts->height; |
196 | |
|
197 | 0 | if (!width || !height) { |
198 | 0 | MP_ERR(demuxer, "rawvideo: width or height not specified!\n"); |
199 | 0 | return -1; |
200 | 0 | } |
201 | | |
202 | 0 | const char *decoder = "rawvideo"; |
203 | 0 | int imgfmt = opts->vformat; |
204 | 0 | int imgsize = opts->imgsize; |
205 | 0 | int mp_imgfmt = 0; |
206 | 0 | if (opts->mp_format && !IMGFMT_IS_HWACCEL(opts->mp_format)) { |
207 | 0 | mp_imgfmt = opts->mp_format; |
208 | 0 | if (!imgsize) { |
209 | 0 | struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(opts->mp_format); |
210 | 0 | for (int p = 0; p < desc.num_planes; p++) { |
211 | 0 | imgsize += ((width >> desc.xs[p]) * (height >> desc.ys[p]) * |
212 | 0 | desc.bpp[p] + 7) / 8; |
213 | 0 | } |
214 | 0 | } |
215 | 0 | } else if (opts->codec && opts->codec[0]) |
216 | 0 | decoder = talloc_strdup(demuxer, opts->codec); |
217 | |
|
218 | 0 | if (!imgsize) { |
219 | 0 | int bpp = 0; |
220 | 0 | switch (imgfmt) { |
221 | 0 | case MKTAG('Y', 'V', '1', '2'): |
222 | 0 | case MKTAG('I', '4', '2', '0'): |
223 | 0 | case MKTAG('I', 'Y', 'U', 'V'): |
224 | 0 | bpp = 12; |
225 | 0 | break; |
226 | 0 | case MKTAG('U', 'Y', 'V', 'Y'): |
227 | 0 | case MKTAG('Y', 'U', 'Y', '2'): |
228 | 0 | bpp = 16; |
229 | 0 | break; |
230 | 0 | } |
231 | 0 | if (!bpp) { |
232 | 0 | MP_ERR(demuxer, "rawvideo: img size not specified and unknown format!\n"); |
233 | 0 | return -1; |
234 | 0 | } |
235 | 0 | imgsize = width * height * bpp / 8; |
236 | 0 | } |
237 | | |
238 | 0 | struct sh_stream *sh = demux_alloc_sh_stream(STREAM_VIDEO); |
239 | 0 | struct mp_codec_params *c = sh->codec; |
240 | 0 | c->codec = decoder; |
241 | 0 | c->codec_tag = imgfmt; |
242 | 0 | c->fps = opts->fps; |
243 | 0 | c->reliable_fps = true; |
244 | 0 | c->disp_w = width; |
245 | 0 | c->disp_h = height; |
246 | 0 | if (mp_imgfmt) { |
247 | 0 | c->lav_codecpar = avcodec_parameters_alloc(); |
248 | 0 | MP_HANDLE_OOM(c->lav_codecpar); |
249 | 0 | c->lav_codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
250 | 0 | c->lav_codecpar->codec_id = mp_codec_to_av_codec_id(decoder); |
251 | 0 | c->lav_codecpar->format = imgfmt2pixfmt(mp_imgfmt); |
252 | 0 | c->lav_codecpar->width = width; |
253 | 0 | c->lav_codecpar->height = height; |
254 | 0 | } |
255 | 0 | demux_add_sh_stream(demuxer, sh); |
256 | |
|
257 | 0 | struct priv *p = talloc_ptrtype(demuxer, p); |
258 | 0 | demuxer->priv = p; |
259 | 0 | *p = (struct priv) { |
260 | 0 | .sh = sh, |
261 | 0 | .frame_size = imgsize, |
262 | 0 | .frame_rate = c->fps, |
263 | 0 | .read_frames = 1, |
264 | 0 | }; |
265 | |
|
266 | 0 | return generic_open(demuxer); |
267 | 0 | } |
268 | | |
269 | | static bool raw_read_packet(struct demuxer *demuxer, struct demux_packet **pkt) |
270 | 0 | { |
271 | 0 | struct priv *p = demuxer->priv; |
272 | |
|
273 | 0 | if (demuxer->stream->eof) |
274 | 0 | return false; |
275 | | |
276 | 0 | struct demux_packet *dp = new_demux_packet(demuxer->packet_pool, |
277 | 0 | p->frame_size * p->read_frames); |
278 | 0 | if (!dp) { |
279 | 0 | MP_ERR(demuxer, "Can't read packet.\n"); |
280 | 0 | return true; |
281 | 0 | } |
282 | | |
283 | 0 | dp->keyframe = true; |
284 | 0 | dp->pos = stream_tell(demuxer->stream); |
285 | 0 | dp->pts = (dp->pos / p->frame_size) / p->frame_rate; |
286 | |
|
287 | 0 | int len = stream_read(demuxer->stream, dp->buffer, dp->len); |
288 | 0 | demux_packet_shorten(dp, len); |
289 | |
|
290 | 0 | dp->stream = p->sh->index; |
291 | 0 | *pkt = dp; |
292 | |
|
293 | 0 | return true; |
294 | 0 | } |
295 | | |
296 | | static void raw_seek(demuxer_t *demuxer, double seek_pts, int flags) |
297 | 0 | { |
298 | 0 | struct priv *p = demuxer->priv; |
299 | 0 | stream_t *s = demuxer->stream; |
300 | 0 | int64_t end = stream_get_size(s); |
301 | 0 | int64_t frame_nr = seek_pts * p->frame_rate; |
302 | 0 | frame_nr = frame_nr - (frame_nr % p->read_frames); |
303 | 0 | int64_t pos = frame_nr * p->frame_size; |
304 | 0 | if (flags & SEEK_FACTOR) |
305 | 0 | pos = end * seek_pts; |
306 | 0 | if (pos < 0) |
307 | 0 | pos = 0; |
308 | 0 | if (end > 0 && pos > end) |
309 | 0 | pos = end; |
310 | 0 | stream_seek(s, (pos / p->frame_size) * p->frame_size); |
311 | 0 | } |
312 | | |
313 | | const demuxer_desc_t demuxer_desc_rawaudio = { |
314 | | .name = "rawaudio", |
315 | | .desc = "Uncompressed audio", |
316 | | .open = demux_rawaudio_open, |
317 | | .read_packet = raw_read_packet, |
318 | | .seek = raw_seek, |
319 | | }; |
320 | | |
321 | | const demuxer_desc_t demuxer_desc_rawvideo = { |
322 | | .name = "rawvideo", |
323 | | .desc = "Uncompressed video", |
324 | | .open = demux_rawvideo_open, |
325 | | .read_packet = raw_read_packet, |
326 | | .seek = raw_seek, |
327 | | }; |