lossless jpeg decoding support

Originally committed as revision 1959 to svn://svn.ffmpeg.org/ffmpeg/trunk
pull/126/head
Michael Niedermayer 22 years ago
parent 31319a8ccd
commit e4d2b1f39a
  1. 208
      libavcodec/mjpeg.c

@ -27,6 +27,8 @@
*/
//#define DEBUG
#include <assert.h>
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
@ -279,6 +281,20 @@ void mjpeg_close(MpegEncContext *s)
av_free(s->mjpeg_ctx);
}
static inline int predict(uint8_t *ptr, int stride, int predictor, int size){
switch(predictor){
case 0: return ptr[0];
case 1: return ptr[-size];
case 2: return ptr[-stride];
case 3: return ptr[-stride-size];
case 4: return ptr[-size] + ptr[-stride] - ptr[-stride-size];
case 5: return ptr[-size] + ((ptr[-stride] - ptr[-stride-size])>>1);
case 6: return ptr[-stride] + ((ptr[-size] - ptr[-stride-size])>>1);
case 7: return (ptr[-size] + ptr[-stride])>>1;
default: return 0xFFFF;
}
}
static inline void put_marker(PutBitContext *p, int code)
{
put_bits(p, 8, 0xff);
@ -653,6 +669,8 @@ typedef struct MJpegDecodeContext {
int first_picture; /* true if decoding first picture */
int interlaced; /* true if interlaced */
int bottom_field; /* true if bottom field */
int lossless;
int rgb;
int width, height;
int nb_components;
@ -810,15 +828,16 @@ static int mjpeg_decode_dht(MJpegDecodeContext *s)
return 0;
}
static int mjpeg_decode_sof0(MJpegDecodeContext *s)
static int mjpeg_decode_sof(MJpegDecodeContext *s)
{
int len, nb_components, i, width, height;
/* XXX: verify len field validity */
len = get_bits(&s->gb, 16);
/* only 8 bits/component accepted */
if (get_bits(&s->gb, 8) != 8)
if (get_bits(&s->gb, 8) != 8){
printf("only 8 bits/component accepted\n");
return -1;
}
height = get_bits(&s->gb, 16);
width = get_bits(&s->gb, 16);
dprintf("sof0: picture: %dx%d\n", width, height);
@ -863,6 +882,17 @@ static int mjpeg_decode_sof0(MJpegDecodeContext *s)
s->bottom_field = 0;
}
assert(s->rgb==0 || (s->h_max==1 && s->v_max==1));
if(s->rgb){
int w, h;
w = s->width;
h = s->height;
if (s->interlaced)
w *= 2;
s->linesize[0] = 4*w;
s->current_picture[0] = av_mallocz(4*w * h);
s->current_picture[1] = s->current_picture[2] = NULL;
}else{
for(i=0;i<nb_components;i++) {
int w, h;
w = (s->width + 8 * s->h_max - 1) / (8 * s->h_max);
@ -879,6 +909,7 @@ static int mjpeg_decode_sof0(MJpegDecodeContext *s)
return -1;
}
}
}
s->first_picture = 0;
}
@ -957,9 +988,12 @@ static int decode_block(MJpegDecodeContext *s, DCTELEM *block,
return 0;
}
static void decode_lossless(MJpegDecodeContext *s, int point_transform, int predictor){
}
static int mjpeg_decode_sos(MJpegDecodeContext *s)
{
int len, nb_components, i, j, n, h, v, ret;
int len, nb_components, i, j, n, h, v, ret, point_transform, predictor;
int mb_width, mb_height, mb_x, mb_y, vmax, hmax, index, id;
int comp_index[4];
int dc_index[4];
@ -967,6 +1001,7 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s)
int nb_blocks[4];
int h_count[4];
int v_count[4];
const int block_size= s->lossless ? 1 : 8;
/* XXX: verify len field validity */
len = get_bits(&s->gb, 16);
@ -1025,40 +1060,174 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s)
break;
}
}
skip_bits(&s->gb, 8); /* Ss */
predictor= get_bits(&s->gb, 8); /* lossless predictor or start of spectral (Ss) */
skip_bits(&s->gb, 8); /* Se */
skip_bits(&s->gb, 8); /* Ah and Al (each are 4 bits) */
skip_bits(&s->gb, 4); /* Ah */
point_transform= get_bits(&s->gb, 4); /* Al */
for(i=0;i<nb_components;i++)
s->last_dc[i] = 1024;
if (nb_components > 1) {
/* interleaved stream */
mb_width = (s->width + s->h_max * 8 - 1) / (s->h_max * 8);
mb_height = (s->height + s->v_max * 8 - 1) / (s->v_max * 8);
mb_width = (s->width + s->h_max * block_size - 1) / (s->h_max * block_size);
mb_height = (s->height + s->v_max * block_size - 1) / (s->v_max * block_size);
} else {
h = s->h_max / s->h_count[comp_index[0]];
v = s->v_max / s->v_count[comp_index[0]];
mb_width = (s->width + h * 8 - 1) / (h * 8);
mb_height = (s->height + v * 8 - 1) / (v * 8);
mb_width = (s->width + h * block_size - 1) / (h * block_size);
mb_height = (s->height + v * block_size - 1) / (v * block_size);
nb_blocks[0] = 1;
h_count[0] = 1;
v_count[0] = 1;
}
if(s->lossless){
if(s->rgb){ //FIXME cleanup
const int linesize= s->linesize[0];
for(mb_y = 0; mb_y < mb_height; mb_y++) {
for(mb_x = 0; mb_x < mb_width; mb_x++) {
if (s->restart_interval && !s->restart_count)
s->restart_count = s->restart_interval;
if(mb_x==0 || mb_y==0 || s->interlaced || 1){
for(i=0;i<3;i++) {
uint8_t *ptr;
int c, pred;
c = comp_index[i];
ptr = s->current_picture[0] + (linesize * mb_y) + 4*mb_x + c; //FIXME optimize this crap
if(mb_y==0){
if(mb_x==0){
pred= 128 << point_transform;
}else{
pred= ptr[-4];
}
}else{
if(mb_x==0){
pred= ptr[-linesize];
}else{
pred= predict(ptr, linesize, predictor, 4);
}
}
if (s->interlaced && s->bottom_field)
ptr += linesize >> 1;
*ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform);
}
}else{
for(i=0;i<3;i++) {
uint8_t *ptr;
int c, pred;
c = comp_index[i];
ptr = s->current_picture[0] + (linesize * mb_y) + 4*mb_x + c; //FIXME optimize this crap
pred= predict(ptr, linesize, predictor, 4);
*ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform);
}
}
/* (< 1350) buggy workaround for Spectralfan.mov, should be fixed */
if (s->restart_interval && (s->restart_interval < 1350) &&
!--s->restart_count) {
align_get_bits(&s->gb);
skip_bits(&s->gb, 16); /* skip RSTn */
}
}
}
}else{
for(mb_y = 0; mb_y < mb_height; mb_y++) {
for(mb_x = 0; mb_x < mb_width; mb_x++) {
if (s->restart_interval && !s->restart_count)
s->restart_count = s->restart_interval;
if(mb_x==0 || mb_y==0 || s->interlaced || 1){
for(i=0;i<nb_components;i++) {
uint8_t *ptr;
int x, y, c;
int x, y, c, linesize;
n = nb_blocks[i];
c = comp_index[i];
h = h_count[i];
v = v_count[i];
x = 0;
y = 0;
linesize= s->linesize[c];
for(j=0; j<n; j++) {
int pred;
ptr = s->current_picture[c] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap
if(y==0 && mb_y==0){
if(x==0 && mb_x==0){
pred= 128 << point_transform;
}else{
pred= ptr[-1];
}
}else{
if(x==0 && mb_x==0){
pred= ptr[-linesize];
}else{
pred= predict(ptr, linesize, predictor, 1);
}
}
if (s->interlaced && s->bottom_field)
ptr += linesize >> 1;
*ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform);
if (++x == h) {
x = 0;
y++;
}
}
}
}else{
for(i=0;i<nb_components;i++) {
uint8_t *ptr;
int x, y, c, linesize;
n = nb_blocks[i];
c = comp_index[i];
h = h_count[i];
v = v_count[i];
x = 0;
y = 0;
linesize= s->linesize[c];
for(j=0; j<n; j++) {
int pred;
ptr = s->current_picture[c] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap
pred= predict(ptr, linesize, predictor, 1);
*ptr= pred + (mjpeg_decode_dc(s, dc_index[i]) << point_transform);
if (++x == h) {
x = 0;
y++;
}
}
}
}
/* (< 1350) buggy workaround for Spectralfan.mov, should be fixed */
if (s->restart_interval && (s->restart_interval < 1350) &&
!--s->restart_count) {
align_get_bits(&s->gb);
skip_bits(&s->gb, 16); /* skip RSTn */
}
}
}
}
}else{
for(mb_y = 0; mb_y < mb_height; mb_y++) {
for(mb_x = 0; mb_x < mb_width; mb_x++) {
if (s->restart_interval && !s->restart_count)
s->restart_count = s->restart_interval;
for(i=0;i<nb_components;i++) {
uint8_t *ptr;
int x, y, c;
n = nb_blocks[i];
c = comp_index[i];
h = h_count[i];
v = v_count[i];
x = 0;
y = 0;
for(j=0;j<n;j++) {
memset(s->block, 0, sizeof(s->block));
if (decode_block(s, s->block, i,
@ -1091,6 +1260,7 @@ static int mjpeg_decode_sos(MJpegDecodeContext *s)
}
}
}
}
ret = 0;
the_end:
emms_c();
@ -1418,7 +1588,15 @@ static int mjpeg_decode_frame(AVCodecContext *avctx,
mjpeg_decode_dht(s);
break;
case SOF0:
if (mjpeg_decode_sof0(s) < 0)
s->lossless=0;
s->rgb=0;
if (mjpeg_decode_sof(s) < 0)
return -1;
break;
case SOF3:
s->lossless=1;
s->rgb=1; //FIXME
if (mjpeg_decode_sof(s) < 0)
return -1;
break;
case EOI:
@ -1443,6 +1621,9 @@ eoi_parser:
/* XXX: not complete test ! */
switch((s->h_count[0] << 4) | s->v_count[0]) {
case 0x11:
if(s->rgb){
avctx->pix_fmt = PIX_FMT_RGBA32;
}else
avctx->pix_fmt = PIX_FMT_YUV444P;
break;
case 0x21:
@ -1471,7 +1652,6 @@ eoi_parser:
break;
case SOF1:
case SOF2:
case SOF3:
case SOF5:
case SOF6:
case SOF7:
@ -1570,7 +1750,7 @@ read_header:
{
init_get_bits(&s->gb, buf+sof_offs, (buf_end - (buf+sof_offs))*8);
s->start_code = SOF0;
if (mjpeg_decode_sof0(s) < 0)
if (mjpeg_decode_sof(s) < 0)
return -1;
}

Loading…
Cancel
Save