1 /*
2  * This file is part of MPlayer.
3  *
4  * MPlayer is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * MPlayer is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "config.h"
24 #include "mp_msg.h"
25 
26 #include "m_option.h"
27 
28 #include "codec-cfg.h"
29 #include "stream/stream.h"
30 #include "libmpdemux/demuxer.h"
31 #include "libmpdemux/stheader.h"
32 
33 #include "stream/stream.h"
34 #include "libmpdemux/muxer.h"
35 
36 #include "img_format.h"
37 #include "mp_image.h"
38 #include "vf.h"
39 
40 #include "libavutil/intreadwrite.h"
41 #include <lzo/lzo1x.h>
42 #include "native/rtjpegn.h"
43 
44 #define LZO_AL(size) (((size) + (sizeof(long) - 1)) / sizeof(long))
45 #define LZO_OUT_LEN(in)     ((in) + (in) / 64 + 16 + 3)
46 
47 //===========================================================================//
48 
49 struct vf_priv_s {
50   int raw; // Do not use RTjpeg
51   int lzo; // Use lzo
52   unsigned int l,c,q; // Mjpeg param
53   muxer_stream_t* mux;
54   uint8_t* buffer;
55 
56   int buf_size;
57   int tbl_wrote;
58   lzo_byte *zbuffer;
59   long __LZO_MMODEL *zmem;
60 };
61 #define mux_v (vf->priv->mux)
62 
63 struct vf_priv_s nuv_priv_dflt = {
64   0, // raw
65   1, // lzo
66   1,1, // l,c
67   255, // q
68   NULL,
69   NULL,
70   0,0,
71   NULL,NULL
72 };
73 
74 const m_option_t nuvopts_conf[] = {
75   {"raw", &nuv_priv_dflt.raw, CONF_TYPE_FLAG, 0, 0, 1, NULL},
76   {"rtjpeg", &nuv_priv_dflt.raw, CONF_TYPE_FLAG, 0, 1, 0, NULL},
77   {"lzo", &nuv_priv_dflt.lzo, CONF_TYPE_FLAG, 0, 0, 1, NULL},
78   {"nolzo", &nuv_priv_dflt.lzo, CONF_TYPE_FLAG, 0, 1, 0, NULL},
79   {"q", &nuv_priv_dflt.q, CONF_TYPE_INT, M_OPT_RANGE,3,255, NULL},
80   {"l", &nuv_priv_dflt.l, CONF_TYPE_INT, M_OPT_RANGE,0,20, NULL},
81   {"c", &nuv_priv_dflt.c, CONF_TYPE_INT, M_OPT_RANGE,0,20, NULL},
82   {NULL, NULL, 0, 0, 0, 0, NULL}
83 };
84 
85 //===========================================================================//
86 
87 
88 #define COMPDATASIZE (128*4)
89 #define FRAMEHEADERSIZE 12
90 
config(struct vf_instance * vf,int width,int height,int d_width,int d_height,unsigned int flags,unsigned int outfmt)91 static int config(struct vf_instance *vf,
92         int width, int height, int d_width, int d_height,
93 	unsigned int flags, unsigned int outfmt){
94 
95   // We need a buffer wich can holda header and a whole YV12 picture
96   // or a RTJpeg table
97   vf->priv->buf_size = width*height*3/2+FRAMEHEADERSIZE;
98   if(vf->priv->buf_size < COMPDATASIZE + FRAMEHEADERSIZE)
99     vf->priv->buf_size = COMPDATASIZE + FRAMEHEADERSIZE;
100 
101   mux_v->bih->biWidth=width;
102   mux_v->bih->biHeight=height;
103   mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8);
104   mux_v->aspect = (float)d_width/d_height;
105   vf->priv->buffer = realloc(vf->priv->buffer,vf->priv->buf_size);
106   if (vf->priv->lzo)
107     vf->priv->zbuffer = realloc(vf->priv->zbuffer, FRAMEHEADERSIZE + LZO_OUT_LEN(vf->priv->buf_size));
108   vf->priv->tbl_wrote = 0;
109 
110   return 1;
111 }
112 
control(struct vf_instance * vf,int request,void * data)113 static int control(struct vf_instance *vf, int request, void* data){
114 
115   return CONTROL_UNKNOWN;
116 }
117 
query_format(struct vf_instance * vf,unsigned int fmt)118 static int query_format(struct vf_instance *vf, unsigned int fmt){
119   if(fmt==IMGFMT_I420) return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW;
120   return 0;
121 }
122 
put_image(struct vf_instance * vf,mp_image_t * mpi,double pts)123 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
124   uint8_t *header  = vf->priv->buffer;
125   uint8_t* data = vf->priv->buffer + FRAMEHEADERSIZE;
126   uint8_t* zdata = vf->priv->zbuffer + FRAMEHEADERSIZE;
127   int len = 0, r;
128   size_t zlen = 0;
129 
130   memset(header, 0, FRAMEHEADERSIZE); // Reset the header
131   if(vf->priv->lzo)
132     memset(vf->priv->zbuffer,0,FRAMEHEADERSIZE);
133 
134   // This has to be don here otherwise tv with sound doesn't work
135   if(!vf->priv->tbl_wrote) {
136     RTjpeg_init_compress((uint32_t *)data,mpi->width,mpi->height,vf->priv->q);
137     RTjpeg_init_mcompress();
138 
139     header[0] = 'D'; // frametype: compressor data
140     header[1] = 'R'; // comptype:  compressor data for RTjpeg
141     AV_WL32(header + 8, COMPDATASIZE); // packetlength
142 
143     mux_v->buffer=vf->priv->buffer;
144     muxer_write_chunk(mux_v,FRAMEHEADERSIZE + COMPDATASIZE, 0x10, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
145     vf->priv->tbl_wrote = 1;
146     memset(header, 0, FRAMEHEADERSIZE); // Reset the header
147   }
148 
149   // Raw picture
150   if(vf->priv->raw) {
151     len = mpi->width*mpi->height*3/2;
152     // Try lzo ???
153     if(vf->priv->lzo) {
154       r = lzo1x_1_compress(mpi->planes[0],len,
155 			   zdata,&zlen,vf->priv->zmem);
156       if(r != LZO_E_OK) {
157 	mp_msg(MSGT_VFILTER,MSGL_ERR,"LZO compress error\n");
158 	zlen = 0;
159       }
160     }
161 
162     if(zlen <= 0 || zlen > len) {
163       memcpy(data,mpi->planes[0],len);
164       header[1] = '0'; // comptype: uncompressed
165     } else { // Use lzo only if it's littler
166       header = vf->priv->zbuffer;
167       header[1] = '3'; //comptype: lzo
168       len = zlen;
169     }
170 
171   } else { // RTjpeg compression
172     len = RTjpeg_mcompressYUV420(data,mpi->planes[0],vf->priv->l,
173 				 vf->priv->c);
174     if(len <= 0) {
175       mp_msg(MSGT_VFILTER,MSGL_ERR,"RTjpeg_mcompressYUV420 error (%d)\n",len);
176       return 0;
177     }
178 
179     if(vf->priv->lzo) {
180       r = lzo1x_1_compress(data,len,zdata,&zlen,vf->priv->zmem);
181       if(r != LZO_E_OK) {
182 	mp_msg(MSGT_VFILTER,MSGL_ERR,"LZO compress error\n");
183 	zlen = 0;
184       }
185     }
186 
187     if(zlen <= 0 || zlen > len)
188       header[1] = '1'; // comptype: RTjpeg
189     else {
190       header = vf->priv->zbuffer;
191       header[1] = '2'; // comptype: RTjpeg + LZO
192       len = zlen;
193     }
194 
195   }
196 
197   header[0] = 'V'; // frametype: video frame
198   AV_WL32(header + 8, len); // packetlength
199   mux_v->buffer = header;
200   muxer_write_chunk(mux_v, len + FRAMEHEADERSIZE, 0x10, pts, pts);
201   return 1;
202 }
203 
uninit(struct vf_instance * vf)204 static void uninit(struct vf_instance *vf) {
205 
206   free(vf->priv->buffer);
207   free(vf->priv->zbuffer);
208   free(vf->priv->zmem);
209 
210 }
211 
212 //===========================================================================//
213 
vf_open(vf_instance_t * vf,char * args)214 static int vf_open(vf_instance_t *vf, char* args){
215   vf->config=config;
216   vf->default_caps=VFCAP_CONSTANT;
217   vf->control=control;
218   vf->query_format=query_format;
219   vf->put_image=put_image;
220   vf->uninit = uninit;
221   vf->priv=malloc(sizeof(struct vf_priv_s));
222   memcpy(vf->priv, &nuv_priv_dflt,sizeof(struct vf_priv_s));
223   vf->priv->mux=(muxer_stream_t*)args;
224 
225   mux_v->bih=calloc(1, sizeof(*mux_v->bih));
226   mux_v->bih->biSize=sizeof(*mux_v->bih);
227   mux_v->bih->biWidth=0;
228   mux_v->bih->biHeight=0;
229   mux_v->bih->biPlanes=1;
230   mux_v->bih->biBitCount=12;
231   mux_v->bih->biCompression = mmioFOURCC('N','U','V','1');
232 
233   if(vf->priv->lzo) {
234     if(lzo_init() != LZO_E_OK) {
235       mp_msg(MSGT_VFILTER,MSGL_WARN,"LZO init failed: no lzo compression\n");
236       vf->priv->lzo = 0;
237     } else
238     vf->priv->zmem = malloc(sizeof(long)*LZO_AL(LZO1X_1_MEM_COMPRESS));
239   }
240 
241   return 1;
242 }
243 
244 const vf_info_t ve_info_nuv = {
245   "nuv encoder",
246   "nuv",
247   "Albeu",
248   "for internal use by mencoder",
249   vf_open
250 };
251 
252 //===========================================================================//
253