1/* 2 * MJPEG/AVI1 to JPEG/JFIF bitstream format filter 3 * Copyright (c) 2010 Adrian Daerr and Nicolas George 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/* 23 * Adapted from mjpeg2jpeg.c, with original copyright: 24 * Paris 2010 Adrian Daerr, public domain 25 */ 26 27#include <string.h> 28#include "avcodec.h" 29#include "mjpeg.h" 30 31static const uint8_t jpeg_header[] = { 32 0xff, 0xd8, // SOI 33 0xff, 0xe0, // APP0 34 0x00, 0x10, // APP0 header size (including 35 // this field, but excluding preceding) 36 0x4a, 0x46, 0x49, 0x46, 0x00, // ID string 'JFIF\0' 37 0x01, 0x01, // version 38 0x00, // bits per type 39 0x00, 0x00, // X density 40 0x00, 0x00, // Y density 41 0x00, // X thumbnail size 42 0x00, // Y thumbnail size 43}; 44 45static const int dht_segment_size = 420; 46static const uint8_t dht_segment_head[] = { 0xFF, 0xC4, 0x01, 0xA2, 0x00 }; 47static const uint8_t dht_segment_frag[] = { 48 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 49 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 50 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 51}; 52 53static uint8_t *append(uint8_t *buf, const uint8_t *src, int size) 54{ 55 memcpy(buf, src, size); 56 return buf + size; 57} 58 59static uint8_t *append_dht_segment(uint8_t *buf) 60{ 61 buf = append(buf, dht_segment_head, sizeof(dht_segment_head)); 62 buf = append(buf, ff_mjpeg_bits_dc_luminance + 1, 16); 63 buf = append(buf, dht_segment_frag, sizeof(dht_segment_frag)); 64 buf = append(buf, ff_mjpeg_val_dc, 12); 65 *(buf++) = 0x10; 66 buf = append(buf, ff_mjpeg_bits_ac_luminance + 1, 16); 67 buf = append(buf, ff_mjpeg_val_ac_luminance, 162); 68 *(buf++) = 0x11; 69 buf = append(buf, ff_mjpeg_bits_ac_chrominance + 1, 16); 70 buf = append(buf, ff_mjpeg_val_ac_chrominance, 162); 71 return buf; 72} 73 74static int mjpeg2jpeg_filter(AVBitStreamFilterContext *bsfc, 75 AVCodecContext *avctx, const char *args, 76 uint8_t **poutbuf, int *poutbuf_size, 77 const uint8_t *buf, int buf_size, 78 int keyframe) 79{ 80 int input_skip, output_size; 81 uint8_t *output, *out; 82 83 if (buf_size < 12) { 84 av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); 85 return AVERROR_INVALIDDATA; 86 } 87 if (memcmp("AVI1", buf + 6, 4)) { 88 av_log(avctx, AV_LOG_ERROR, "input is not MJPEG/AVI1\n"); 89 return AVERROR_INVALIDDATA; 90 } 91 input_skip = (buf[4] << 8) + buf[5] + 4; 92 if (buf_size < input_skip) { 93 av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); 94 return AVERROR_INVALIDDATA; 95 } 96 output_size = buf_size - input_skip + 97 sizeof(jpeg_header) + dht_segment_size; 98 output = out = av_malloc(output_size); 99 if (!output) 100 return AVERROR(ENOMEM); 101 out = append(out, jpeg_header, sizeof(jpeg_header)); 102 out = append_dht_segment(out); 103 out = append(out, buf + input_skip, buf_size - input_skip); 104 *poutbuf = output; 105 *poutbuf_size = output_size; 106 return 1; 107} 108 109AVBitStreamFilter ff_mjpeg2jpeg_bsf = { 110 .name = "mjpeg2jpeg", 111 .filter = mjpeg2jpeg_filter, 112}; 113