blob: ca5fb3a37737b739eab0c812010b9bb6af02e8e6
1 | /* |
2 | * MJPEG A dump header bitstream filter |
3 | * Copyright (c) 2006 Baptiste Coudurier |
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 | |
22 | /** |
23 | * @file |
24 | * MJPEG A dump header bitstream filter |
25 | * modifies bitstream to be decoded by quicktime |
26 | */ |
27 | |
28 | #include "avcodec.h" |
29 | #include "bsf.h" |
30 | #include "bytestream.h" |
31 | #include "mjpeg.h" |
32 | |
33 | |
34 | static int mjpega_dump_header(AVBSFContext *ctx, AVPacket *out) |
35 | { |
36 | AVPacket *in; |
37 | uint8_t *out_buf; |
38 | unsigned dqt = 0, dht = 0, sof0 = 0; |
39 | int ret = 0, i; |
40 | |
41 | ret = ff_bsf_get_packet(ctx, &in); |
42 | if (ret < 0) |
43 | return ret; |
44 | |
45 | ret = av_new_packet(out, in->size + 44); |
46 | if (ret < 0) |
47 | goto fail; |
48 | |
49 | ret = av_packet_copy_props(out, in); |
50 | if (ret < 0) |
51 | goto fail; |
52 | |
53 | out_buf = out->data; |
54 | bytestream_put_byte(&out_buf, 0xff); |
55 | bytestream_put_byte(&out_buf, SOI); |
56 | bytestream_put_byte(&out_buf, 0xff); |
57 | bytestream_put_byte(&out_buf, APP1); |
58 | bytestream_put_be16(&out_buf, 42); /* size */ |
59 | bytestream_put_be32(&out_buf, 0); |
60 | bytestream_put_buffer(&out_buf, "mjpg", 4); |
61 | bytestream_put_be32(&out_buf, in->size + 44); /* field size */ |
62 | bytestream_put_be32(&out_buf, in->size + 44); /* pad field size */ |
63 | bytestream_put_be32(&out_buf, 0); /* next ptr */ |
64 | |
65 | for (i = 0; i < in->size - 1; i++) { |
66 | if (in->data[i] == 0xff) { |
67 | switch (in->data[i + 1]) { |
68 | case DQT: dqt = i + 46; break; |
69 | case DHT: dht = i + 46; break; |
70 | case SOF0: sof0 = i + 46; break; |
71 | case SOS: |
72 | bytestream_put_be32(&out_buf, dqt); /* quant off */ |
73 | bytestream_put_be32(&out_buf, dht); /* huff off */ |
74 | bytestream_put_be32(&out_buf, sof0); /* image off */ |
75 | bytestream_put_be32(&out_buf, i + 46); /* scan off */ |
76 | bytestream_put_be32(&out_buf, i + 46 + AV_RB16(in->data + i + 2)); /* data off */ |
77 | bytestream_put_buffer(&out_buf, in->data + 2, in->size - 2); /* skip already written SOI */ |
78 | |
79 | out->size = out_buf - out->data; |
80 | av_packet_free(&in); |
81 | return 0; |
82 | case APP1: |
83 | if (i + 8 < in->size && AV_RL32(in->data + i + 8) == AV_RL32("mjpg")) { |
84 | av_log(ctx, AV_LOG_ERROR, "bitstream already formatted\n"); |
85 | av_packet_unref(out); |
86 | av_packet_move_ref(out, in); |
87 | av_packet_free(&in); |
88 | return 0; |
89 | } |
90 | } |
91 | } |
92 | } |
93 | av_log(ctx, AV_LOG_ERROR, "could not find SOS marker in bitstream\n"); |
94 | fail: |
95 | av_packet_unref(out); |
96 | av_packet_free(&in); |
97 | return AVERROR_INVALIDDATA; |
98 | } |
99 | |
100 | static const enum AVCodecID codec_ids[] = { |
101 | AV_CODEC_ID_MJPEG, AV_CODEC_ID_NONE, |
102 | }; |
103 | |
104 | const AVBitStreamFilter ff_mjpega_dump_header_bsf = { |
105 | .name = "mjpegadump", |
106 | .filter = mjpega_dump_header, |
107 | .codec_ids = codec_ids, |
108 | }; |
109 |