You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

321 lines
12KB

  1. /*
  2. * YUV4MPEG demuxer
  3. * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avformat.h"
  22. #include "internal.h"
  23. #include "yuv4mpeg.h"
  24. /* Header size increased to allow room for optional flags */
  25. #define MAX_YUV4_HEADER 80
  26. #define MAX_FRAME_HEADER 80
  27. static int yuv4_read_header(AVFormatContext *s)
  28. {
  29. char header[MAX_YUV4_HEADER + 10]; // Include headroom for
  30. // the longest option
  31. char *tokstart, *tokend, *header_end;
  32. int i;
  33. AVIOContext *pb = s->pb;
  34. int width = -1, height = -1, raten = 0,
  35. rated = 0, aspectn = 0, aspectd = 0;
  36. enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE, alt_pix_fmt = AV_PIX_FMT_NONE;
  37. enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED;
  38. AVStream *st;
  39. enum AVFieldOrder field_order;
  40. for (i = 0; i < MAX_YUV4_HEADER; i++) {
  41. header[i] = avio_r8(pb);
  42. if (header[i] == '\n') {
  43. header[i + 1] = 0x20; // Add a space after last option.
  44. // Makes parsing "444" vs "444alpha" easier.
  45. header[i + 2] = 0;
  46. break;
  47. }
  48. }
  49. if (i == MAX_YUV4_HEADER)
  50. return -1;
  51. if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC)))
  52. return -1;
  53. header_end = &header[i + 1]; // Include space
  54. for (tokstart = &header[strlen(Y4M_MAGIC) + 1];
  55. tokstart < header_end; tokstart++) {
  56. if (*tokstart == 0x20)
  57. continue;
  58. switch (*tokstart++) {
  59. case 'W': // Width. Required.
  60. width = strtol(tokstart, &tokend, 10);
  61. tokstart = tokend;
  62. break;
  63. case 'H': // Height. Required.
  64. height = strtol(tokstart, &tokend, 10);
  65. tokstart = tokend;
  66. break;
  67. case 'C': // Color space
  68. if (strncmp("420jpeg", tokstart, 7) == 0) {
  69. pix_fmt = AV_PIX_FMT_YUV420P;
  70. chroma_sample_location = AVCHROMA_LOC_CENTER;
  71. } else if (strncmp("420mpeg2", tokstart, 8) == 0) {
  72. pix_fmt = AV_PIX_FMT_YUV420P;
  73. chroma_sample_location = AVCHROMA_LOC_LEFT;
  74. } else if (strncmp("420paldv", tokstart, 8) == 0) {
  75. pix_fmt = AV_PIX_FMT_YUV420P;
  76. chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
  77. } else if (strncmp("420p16", tokstart, 6) == 0) {
  78. pix_fmt = AV_PIX_FMT_YUV420P16;
  79. } else if (strncmp("422p16", tokstart, 6) == 0) {
  80. pix_fmt = AV_PIX_FMT_YUV422P16;
  81. } else if (strncmp("444p16", tokstart, 6) == 0) {
  82. pix_fmt = AV_PIX_FMT_YUV444P16;
  83. } else if (strncmp("420p14", tokstart, 6) == 0) {
  84. pix_fmt = AV_PIX_FMT_YUV420P14;
  85. } else if (strncmp("422p14", tokstart, 6) == 0) {
  86. pix_fmt = AV_PIX_FMT_YUV422P14;
  87. } else if (strncmp("444p14", tokstart, 6) == 0) {
  88. pix_fmt = AV_PIX_FMT_YUV444P14;
  89. } else if (strncmp("420p12", tokstart, 6) == 0) {
  90. pix_fmt = AV_PIX_FMT_YUV420P12;
  91. } else if (strncmp("422p12", tokstart, 6) == 0) {
  92. pix_fmt = AV_PIX_FMT_YUV422P12;
  93. } else if (strncmp("444p12", tokstart, 6) == 0) {
  94. pix_fmt = AV_PIX_FMT_YUV444P12;
  95. } else if (strncmp("420p10", tokstart, 6) == 0) {
  96. pix_fmt = AV_PIX_FMT_YUV420P10;
  97. } else if (strncmp("422p10", tokstart, 6) == 0) {
  98. pix_fmt = AV_PIX_FMT_YUV422P10;
  99. } else if (strncmp("444p10", tokstart, 6) == 0) {
  100. pix_fmt = AV_PIX_FMT_YUV444P10;
  101. } else if (strncmp("420p9", tokstart, 5) == 0) {
  102. pix_fmt = AV_PIX_FMT_YUV420P9;
  103. } else if (strncmp("422p9", tokstart, 5) == 0) {
  104. pix_fmt = AV_PIX_FMT_YUV422P9;
  105. } else if (strncmp("444p9", tokstart, 5) == 0) {
  106. pix_fmt = AV_PIX_FMT_YUV444P9;
  107. } else if (strncmp("420", tokstart, 3) == 0) {
  108. pix_fmt = AV_PIX_FMT_YUV420P;
  109. chroma_sample_location = AVCHROMA_LOC_CENTER;
  110. } else if (strncmp("411", tokstart, 3) == 0) {
  111. pix_fmt = AV_PIX_FMT_YUV411P;
  112. } else if (strncmp("422", tokstart, 3) == 0) {
  113. pix_fmt = AV_PIX_FMT_YUV422P;
  114. } else if (strncmp("444alpha", tokstart, 8) == 0 ) {
  115. av_log(s, AV_LOG_ERROR, "Cannot handle 4:4:4:4 "
  116. "YUV4MPEG stream.\n");
  117. return -1;
  118. } else if (strncmp("444", tokstart, 3) == 0) {
  119. pix_fmt = AV_PIX_FMT_YUV444P;
  120. } else if (strncmp("mono16", tokstart, 6) == 0) {
  121. pix_fmt = AV_PIX_FMT_GRAY16;
  122. } else if (strncmp("mono", tokstart, 4) == 0) {
  123. pix_fmt = AV_PIX_FMT_GRAY8;
  124. } else {
  125. av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown "
  126. "pixel format.\n");
  127. return -1;
  128. }
  129. while (tokstart < header_end && *tokstart != 0x20)
  130. tokstart++;
  131. break;
  132. case 'I': // Interlace type
  133. switch (*tokstart++){
  134. case '?':
  135. field_order = AV_FIELD_UNKNOWN;
  136. break;
  137. case 'p':
  138. field_order = AV_FIELD_PROGRESSIVE;
  139. break;
  140. case 't':
  141. field_order = AV_FIELD_TT;
  142. break;
  143. case 'b':
  144. field_order = AV_FIELD_BB;
  145. break;
  146. case 'm':
  147. av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed "
  148. "interlaced and non-interlaced frames.\n");
  149. default:
  150. av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
  151. return AVERROR(EINVAL);
  152. }
  153. break;
  154. case 'F': // Frame rate
  155. sscanf(tokstart, "%d:%d", &raten, &rated); // 0:0 if unknown
  156. while (tokstart < header_end && *tokstart != 0x20)
  157. tokstart++;
  158. break;
  159. case 'A': // Pixel aspect
  160. sscanf(tokstart, "%d:%d", &aspectn, &aspectd); // 0:0 if unknown
  161. while (tokstart < header_end && *tokstart != 0x20)
  162. tokstart++;
  163. break;
  164. case 'X': // Vendor extensions
  165. if (strncmp("YSCSS=", tokstart, 6) == 0) {
  166. // Older nonstandard pixel format representation
  167. tokstart += 6;
  168. if (strncmp("420JPEG", tokstart, 7) == 0)
  169. alt_pix_fmt = AV_PIX_FMT_YUV420P;
  170. else if (strncmp("420MPEG2", tokstart, 8) == 0)
  171. alt_pix_fmt = AV_PIX_FMT_YUV420P;
  172. else if (strncmp("420PALDV", tokstart, 8) == 0)
  173. alt_pix_fmt = AV_PIX_FMT_YUV420P;
  174. else if (strncmp("420P9", tokstart, 5) == 0)
  175. alt_pix_fmt = AV_PIX_FMT_YUV420P9;
  176. else if (strncmp("422P9", tokstart, 5) == 0)
  177. alt_pix_fmt = AV_PIX_FMT_YUV422P9;
  178. else if (strncmp("444P9", tokstart, 5) == 0)
  179. alt_pix_fmt = AV_PIX_FMT_YUV444P9;
  180. else if (strncmp("420P10", tokstart, 6) == 0)
  181. alt_pix_fmt = AV_PIX_FMT_YUV420P10;
  182. else if (strncmp("422P10", tokstart, 6) == 0)
  183. alt_pix_fmt = AV_PIX_FMT_YUV422P10;
  184. else if (strncmp("444P10", tokstart, 6) == 0)
  185. alt_pix_fmt = AV_PIX_FMT_YUV444P10;
  186. else if (strncmp("420P12", tokstart, 6) == 0)
  187. alt_pix_fmt = AV_PIX_FMT_YUV420P12;
  188. else if (strncmp("422P12", tokstart, 6) == 0)
  189. alt_pix_fmt = AV_PIX_FMT_YUV422P12;
  190. else if (strncmp("444P12", tokstart, 6) == 0)
  191. alt_pix_fmt = AV_PIX_FMT_YUV444P12;
  192. else if (strncmp("420P14", tokstart, 6) == 0)
  193. alt_pix_fmt = AV_PIX_FMT_YUV420P14;
  194. else if (strncmp("422P14", tokstart, 6) == 0)
  195. alt_pix_fmt = AV_PIX_FMT_YUV422P14;
  196. else if (strncmp("444P14", tokstart, 6) == 0)
  197. alt_pix_fmt = AV_PIX_FMT_YUV444P14;
  198. else if (strncmp("420P16", tokstart, 6) == 0)
  199. alt_pix_fmt = AV_PIX_FMT_YUV420P16;
  200. else if (strncmp("422P16", tokstart, 6) == 0)
  201. alt_pix_fmt = AV_PIX_FMT_YUV422P16;
  202. else if (strncmp("444P16", tokstart, 6) == 0)
  203. alt_pix_fmt = AV_PIX_FMT_YUV444P16;
  204. else if (strncmp("411", tokstart, 3) == 0)
  205. alt_pix_fmt = AV_PIX_FMT_YUV411P;
  206. else if (strncmp("422", tokstart, 3) == 0)
  207. alt_pix_fmt = AV_PIX_FMT_YUV422P;
  208. else if (strncmp("444", tokstart, 3) == 0)
  209. alt_pix_fmt = AV_PIX_FMT_YUV444P;
  210. }
  211. while (tokstart < header_end && *tokstart != 0x20)
  212. tokstart++;
  213. break;
  214. }
  215. }
  216. if (width == -1 || height == -1) {
  217. av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
  218. return -1;
  219. }
  220. if (pix_fmt == AV_PIX_FMT_NONE) {
  221. if (alt_pix_fmt == AV_PIX_FMT_NONE)
  222. pix_fmt = AV_PIX_FMT_YUV420P;
  223. else
  224. pix_fmt = alt_pix_fmt;
  225. }
  226. if (raten <= 0 || rated <= 0) {
  227. // Frame rate unknown
  228. raten = 25;
  229. rated = 1;
  230. }
  231. if (aspectn == 0 && aspectd == 0) {
  232. // Pixel aspect unknown
  233. aspectd = 1;
  234. }
  235. st = avformat_new_stream(s, NULL);
  236. if (!st)
  237. return AVERROR(ENOMEM);
  238. st->codec->width = width;
  239. st->codec->height = height;
  240. av_reduce(&raten, &rated, raten, rated, (1UL << 31) - 1);
  241. avpriv_set_pts_info(st, 64, rated, raten);
  242. st->avg_frame_rate = av_inv_q(st->time_base);
  243. st->codec->pix_fmt = pix_fmt;
  244. st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  245. st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
  246. st->sample_aspect_ratio = (AVRational){ aspectn, aspectd };
  247. st->codec->chroma_sample_location = chroma_sample_location;
  248. st->codec->field_order = field_order;
  249. return 0;
  250. }
  251. static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
  252. {
  253. int i;
  254. char header[MAX_FRAME_HEADER+1];
  255. int packet_size, width, height, ret;
  256. AVStream *st = s->streams[0];
  257. for (i = 0; i < MAX_FRAME_HEADER; i++) {
  258. header[i] = avio_r8(s->pb);
  259. if (header[i] == '\n') {
  260. header[i + 1] = 0;
  261. break;
  262. }
  263. }
  264. if (s->pb->error)
  265. return s->pb->error;
  266. else if (s->pb->eof_reached)
  267. return AVERROR_EOF;
  268. else if (i == MAX_FRAME_HEADER)
  269. return AVERROR_INVALIDDATA;
  270. if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC)))
  271. return AVERROR_INVALIDDATA;
  272. width = st->codec->width;
  273. height = st->codec->height;
  274. packet_size = avpicture_get_size(st->codec->pix_fmt, width, height);
  275. if (packet_size < 0)
  276. return packet_size;
  277. ret = av_get_packet(s->pb, pkt, packet_size);
  278. if (ret < 0)
  279. return ret;
  280. else if (ret != packet_size)
  281. return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO);
  282. pkt->stream_index = 0;
  283. return 0;
  284. }
  285. static int yuv4_probe(AVProbeData *pd)
  286. {
  287. /* check file header */
  288. if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC) - 1) == 0)
  289. return AVPROBE_SCORE_MAX;
  290. else
  291. return 0;
  292. }
  293. AVInputFormat ff_yuv4mpegpipe_demuxer = {
  294. .name = "yuv4mpegpipe",
  295. .long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
  296. .read_probe = yuv4_probe,
  297. .read_header = yuv4_read_header,
  298. .read_packet = yuv4_read_packet,
  299. .extensions = "y4m",
  300. };