1 /*******************************************************************************
2  rtjpeg_codec.c
3 
4  libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5  http://libquicktime.sourceforge.net
6 
7  Copyright (C) 2002 Heroine Virtual Ltd.
8  Copyright (C) 2002-2011 Members of the libquicktime project.
9 
10  This library is free software; you can redistribute it and/or modify it under
11  the terms of the GNU Lesser General Public License as published by the Free
12  Software Foundation; either version 2.1 of the License, or (at your option)
13  any later version.
14 
15  This library is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18  details.
19 
20  You should have received a copy of the GNU Lesser General Public License along
21  with this library; if not, write to the Free Software Foundation, Inc., 51
22  Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *******************************************************************************/
24 
25 #include "lqt_private.h"
26 #include "rtjpeg_codec.h"
27 #include <quicktime/colormodels.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #define BLOCK_SIZE 16
32 
delete_codec(quicktime_codec_t * codec_base)33 static int delete_codec(quicktime_codec_t *codec_base)
34   {
35   quicktime_rtjpeg_codec_t *codec = codec_base->priv;
36   if(codec->compress_struct)
37     RTjpeg_close(codec->compress_struct);
38   if(codec->rows)
39     lqt_rows_free(codec->rows);
40   if(codec->write_buffer)
41     free(codec->write_buffer);
42 
43   if(codec->decompress_struct)
44     RTjpeg_close(codec->decompress_struct);
45   if(codec->read_buffer)
46     free(codec->read_buffer);
47   free(codec);
48   return 0;
49   }
50 
decode(quicktime_t * file,unsigned char ** row_pointers,int track)51 static int decode(quicktime_t *file, unsigned char **row_pointers, int track)
52   {
53   int result = 0;
54   int t;
55   int buffer_size;
56   quicktime_video_map_t *vtrack = &file->vtracks[track];
57   //	quicktime_trak_t *trak = vtrack->track;
58   quicktime_rtjpeg_codec_t *codec = vtrack->codec->priv;
59 
60   if(!row_pointers)
61     {
62     vtrack->stream_cmodel = BC_YUV420P;
63     return 0;
64     }
65 
66   if(!codec->decompress_struct) {
67   codec->decompress_struct = RTjpeg_init();
68   if(!codec->decompress_struct)
69     return -1;
70   codec->qt_height = quicktime_video_height(file, track);
71   codec->qt_width  = quicktime_video_width(file, track);
72   codec->jpeg_height = BLOCK_SIZE * ((codec->qt_height + BLOCK_SIZE - 1) / (BLOCK_SIZE));
73   codec->jpeg_width  = BLOCK_SIZE * ((codec->qt_width  + BLOCK_SIZE - 1) / (BLOCK_SIZE));
74   t = RTJ_YUV420;
75   RTjpeg_set_format(codec->decompress_struct, &t);
76 
77   codec->rows = lqt_rows_alloc(codec->jpeg_width, codec->jpeg_height,
78                                vtrack->stream_cmodel, &codec->rowspan,
79                                &codec->rowspan_uv);
80 
81   }
82 
83   buffer_size = lqt_read_video_frame(file, &codec->read_buffer,
84                                      &codec->read_buffer_alloc,
85                                      vtrack->current_position, NULL, track);
86   if(buffer_size <= 0)
87     result = -1;
88 
89   if(buffer_size > 0) {
90   if(!result)
91     RTjpeg_decompress(codec->decompress_struct, codec->read_buffer, codec->rows);
92   }
93 
94   lqt_rows_copy(row_pointers, codec->rows, codec->qt_width, codec->qt_height,
95                 codec->rowspan, codec->rowspan_uv,
96                 vtrack->stream_row_span, vtrack->stream_row_span_uv, vtrack->stream_cmodel);
97 
98 
99   return result;
100   }
101 
encode(quicktime_t * file,unsigned char ** row_pointers,int track)102 static int encode(quicktime_t *file, unsigned char **row_pointers, int track)
103   {
104   int result = 0;
105   int i;
106   quicktime_video_map_t *vtrack = &file->vtracks[track];
107   quicktime_trak_t *trak = vtrack->track;
108   quicktime_rtjpeg_codec_t *codec = vtrack->codec->priv;
109 
110   if(!row_pointers)
111     {
112     vtrack->stream_cmodel = BC_YUV420P;
113     return 0;
114     }
115 
116   if(!codec->compress_struct) {
117   codec->compress_struct = RTjpeg_init();
118   if(!codec->compress_struct)
119     return -1;
120   codec->qt_height = trak->tkhd.track_height;
121   codec->qt_width  = trak->tkhd.track_width;
122   codec->jpeg_height = BLOCK_SIZE * ((codec->qt_height + BLOCK_SIZE - 1) / (BLOCK_SIZE));
123   codec->jpeg_width  = BLOCK_SIZE * ((codec->qt_width  + BLOCK_SIZE - 1) / (BLOCK_SIZE));
124 
125   RTjpeg_set_size(codec->compress_struct, &codec->jpeg_width, &codec->jpeg_height);
126   i = codec->Q;
127   i *= 255;
128   i /= 100;
129   RTjpeg_set_quality(codec->compress_struct, &i);
130   i = RTJ_YUV420;
131   RTjpeg_set_format(codec->compress_struct, &i);
132   RTjpeg_set_intra(codec->compress_struct, &codec->K, &codec->LQ, &codec->CQ);
133 
134   codec->rows = lqt_rows_alloc(codec->jpeg_width, codec->jpeg_height,
135                                vtrack->stream_cmodel, &codec->rowspan,
136                                &codec->rowspan_uv);
137 
138   codec->write_buffer = malloc(codec->jpeg_width * codec->jpeg_height * 3 / 2 + 100);
139   if(!codec->write_buffer)
140     return -1;
141   }
142 
143   lqt_rows_copy(codec->rows, row_pointers, codec->qt_width, codec->qt_height,
144                 vtrack->stream_row_span, vtrack->stream_row_span_uv,
145                 codec->rowspan, codec->rowspan_uv,
146                 vtrack->stream_cmodel);
147 
148 
149   i = RTjpeg_compress(codec->compress_struct, codec->write_buffer, codec->rows);
150 
151   lqt_write_frame_header(file, track,
152                          vtrack->current_position,
153                          -1, 0);
154 
155   result = !quicktime_write_data(file,
156                                  codec->write_buffer,
157                                  i);
158   lqt_write_frame_footer(file, track);
159   return result;
160   }
161 
set_parameter(quicktime_t * file,int track,const char * key,const void * value)162 static int set_parameter(quicktime_t *file,
163                          int track,
164                          const char *key,
165                          const void *value)
166   {
167   quicktime_rtjpeg_codec_t *codec = file->vtracks[track].codec->priv;
168 
169   if(!strcasecmp(key, "rtjpeg_quality"))
170     codec->Q = *(int*)value;
171   if(!strcasecmp(key, "rtjpeg_key_rate"))
172     codec->K = *(int*)value;
173   if(!strcasecmp(key, "rtjpeg_luma_quant"))
174     codec->LQ = *(int*)value;
175   if(!strcasecmp(key, "rtjpeg_chroma_quant"))
176     codec->CQ = *(int*)value;
177   return 0;
178   }
179 
quicktime_init_codec_rtjpeg(quicktime_codec_t * codec_base,quicktime_audio_map_t * atrack,quicktime_video_map_t * vtrack)180 void quicktime_init_codec_rtjpeg(quicktime_codec_t * codec_base,
181                                  quicktime_audio_map_t *atrack,
182                                  quicktime_video_map_t *vtrack)
183   {
184   quicktime_rtjpeg_codec_t *codec;
185 
186   codec = calloc(1, sizeof(*codec));
187   if(!codec)
188     return;
189   codec->Q = 100;
190   codec->K = 25;
191   codec->LQ = 1;
192   codec->CQ = 1;
193 
194   codec_base->priv = codec;
195   codec_base->delete_codec = delete_codec;
196   codec_base->decode_video = decode;
197   codec_base->encode_video = encode;
198   codec_base->set_parameter = set_parameter;
199   }
200