00001 #include <climits>
00002
00003 extern "C" {
00004 #include "libavcodec/avcodec.h"
00005 }
00006 #include "frame.h"
00007 #include "mythlogging.h"
00008 #include "myth_imgconvert.h"
00009 #include "pgm.h"
00010
00011
00012
00013
00014
00015
00016
00017
00018 static enum PixelFormat pixelTypeOfVideoFrameType(VideoFrameType codec)
00019 {
00020
00021 switch (codec) {
00022 case FMT_YV12: return PIX_FMT_YUV420P;
00023 default: break;
00024 }
00025 return PIX_FMT_NONE;
00026 }
00027
00028 int pgm_fill(AVPicture *dst, const VideoFrame *frame)
00029 {
00030 enum PixelFormat srcfmt;
00031 AVPicture src;
00032
00033 if ((srcfmt = pixelTypeOfVideoFrameType(frame->codec)) == PIX_FMT_NONE)
00034 {
00035 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_fill unknown codec: %1")
00036 .arg(frame->codec));
00037 return -1;
00038 }
00039
00040 if (avpicture_fill(&src, frame->buf, srcfmt, frame->width,
00041 frame->height) < 0)
00042 {
00043 LOG(VB_COMMFLAG, LOG_ERR, "pgm_fill avpicture_fill failed");
00044 return -1;
00045 }
00046
00047 if (myth_sws_img_convert(dst, PIX_FMT_GRAY8, &src, srcfmt, frame->width,
00048 frame->height))
00049 {
00050 LOG(VB_COMMFLAG, LOG_ERR, "pgm_fill img_convert failed");
00051 return -1;
00052 }
00053
00054 return 0;
00055 }
00056
00057 int pgm_read(unsigned char *buf, int width, int height, const char *filename)
00058 {
00059 FILE *fp;
00060 int nn, fwidth, fheight, maxgray, rr;
00061
00062 if (!(fp = fopen(filename, "r")))
00063 {
00064 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_read fopen %1 failed: %2")
00065 .arg(filename).arg(strerror(errno)));
00066 return -1;
00067 }
00068
00069 if ((nn = fscanf(fp, "P5\n%20d %20d\n%20d\n",
00070 &fwidth, &fheight, &maxgray)) != 3)
00071 {
00072 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_read fscanf %1 failed: %2")
00073 .arg(filename).arg(strerror(errno)));
00074 goto error;
00075 }
00076
00077 if (fwidth != width || fheight != height || maxgray != UCHAR_MAX)
00078 {
00079 LOG(VB_COMMFLAG, LOG_ERR,
00080 QString("pgm_read header (%1x%2,%3) != (%4x%5,%6)")
00081 .arg(fwidth).arg(fheight).arg(maxgray)
00082 .arg(width).arg(height).arg(UCHAR_MAX));
00083 goto error;
00084 }
00085
00086 for (rr = 0; rr < height; rr++)
00087 {
00088 if (fread(buf + rr * width, 1, width, fp) != (size_t)width)
00089 {
00090 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_read fread %1 failed: %2")
00091 .arg(filename).arg(strerror(errno)));
00092 goto error;
00093 }
00094 }
00095
00096 (void)fclose(fp);
00097 return 0;
00098
00099 error:
00100 (void)fclose(fp);
00101 return -1;
00102 }
00103
00104 int pgm_write(const unsigned char *buf, int width, int height,
00105 const char *filename)
00106 {
00107
00108 FILE *fp;
00109 int rr;
00110
00111 if (!(fp = fopen(filename, "w")))
00112 {
00113 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_write fopen %1 failed: %2")
00114 .arg(filename).arg(strerror(errno)));
00115 return -1;
00116 }
00117
00118 (void)fprintf(fp, "P5\n%d %d\n%d\n", width, height, UCHAR_MAX);
00119 for (rr = 0; rr < height; rr++)
00120 {
00121 if (fwrite(buf + rr * width, 1, width, fp) != (size_t)width)
00122 {
00123 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_write fwrite %1 failed: %2")
00124 .arg(filename).arg(strerror(errno)));
00125 goto error;
00126 }
00127 }
00128
00129 (void)fclose(fp);
00130 return 0;
00131
00132 error:
00133 (void)fclose(fp);
00134 return -1;
00135 }
00136
00137 static int pgm_expand(AVPicture *dst, const AVPicture *src, int srcheight,
00138 int extratop, int extraright, int extrabottom,
00139 int extraleft)
00140 {
00141
00142 const int srcwidth = src->linesize[0];
00143 const int newwidth = srcwidth + extraleft + extraright;
00144 const int newheight = srcheight + extratop + extrabottom;
00145 const unsigned char *srcdata;
00146 int rr;
00147
00148
00149 for (rr = 0; rr < srcheight; rr++)
00150 memcpy(dst->data[0] + (rr + extratop) * newwidth + extraleft,
00151 src->data[0] + rr * srcwidth,
00152 srcwidth);
00153
00154
00155 srcdata = src->data[0];
00156 for (rr = 0; rr < extratop; rr++)
00157 memcpy(dst->data[0] + rr * newwidth + extraleft, srcdata, srcwidth);
00158
00159
00160 srcdata = src->data[0] + (srcheight - 1) * srcwidth;
00161 for (rr = extratop + srcheight; rr < newheight; rr++)
00162 memcpy(dst->data[0] + rr * newwidth + extraleft, srcdata, srcwidth);
00163
00164
00165 for (rr = 0; rr < newheight; rr++)
00166 memset(dst->data[0] + rr * newwidth,
00167 dst->data[0][rr * newwidth + extraleft],
00168 extraleft);
00169
00170
00171 for (rr = 0; rr < newheight; rr++)
00172 memset(dst->data[0] + rr * newwidth + extraleft + srcwidth,
00173 dst->data[0][rr * newwidth + extraleft + srcwidth - 1],
00174 extraright);
00175
00176 return 0;
00177 }
00178
00179 static int pgm_expand_uniform(AVPicture *dst, const AVPicture *src,
00180 int srcheight, int extramargin)
00181 {
00182 return pgm_expand(dst, src, srcheight,
00183 extramargin, extramargin, extramargin, extramargin);
00184 }
00185
00186 int pgm_crop(AVPicture *dst, const AVPicture *src, int srcheight,
00187 int srcrow, int srccol, int cropwidth, int cropheight)
00188 {
00189 const int srcwidth = src->linesize[0];
00190 int rr;
00191
00192 if (dst->linesize[0] != cropwidth)
00193 {
00194 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_crop want width %1, have %2")
00195 .arg(cropwidth).arg(dst->linesize[0]));
00196 return -1;
00197 }
00198
00199 for (rr = 0; rr < cropheight; rr++)
00200 memcpy(dst->data[0] + rr * cropwidth,
00201 src->data[0] + (srcrow + rr) * srcwidth + srccol,
00202 cropwidth);
00203
00204 (void)srcheight;
00205 return 0;
00206 }
00207
00208 int pgm_overlay(AVPicture *dst, const AVPicture *s1, int s1height,
00209 int s1row, int s1col, const AVPicture *s2, int s2height)
00210 {
00211 const int dstwidth = dst->linesize[0];
00212 const int s1width = s1->linesize[0];
00213 const int s2width = s2->linesize[0];
00214 int rr;
00215
00216 if (dstwidth != s1width)
00217 {
00218 LOG(VB_COMMFLAG, LOG_ERR, QString("pgm_overlay want width %1, have %2")
00219 .arg(s1width).arg(dst->linesize[0]));
00220 return -1;
00221 }
00222
00223 av_picture_copy(dst, s1, PIX_FMT_GRAY8, s1width, s1height);
00224
00225
00226 for (rr = 0; rr < s2height; rr++)
00227 memcpy(dst->data[0] + (s1row + rr) * s1width + s1col,
00228 s2->data[0] + rr * s2width,
00229 s2width);
00230
00231 return 0;
00232 }
00233
00234 int pgm_convolve_radial(AVPicture *dst, AVPicture *s1, AVPicture *s2,
00235 const AVPicture *src, int srcheight,
00236 const double *mask, int mask_radius)
00237 {
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 const int srcwidth = src->linesize[0];
00252 const int newwidth = srcwidth + 2 * mask_radius;
00253 const int newheight = srcheight + 2 * mask_radius;
00254 int ii, rr, cc, rr2, cc2;
00255 double sum;
00256
00257
00258 if (pgm_expand_uniform(s1, src, srcheight, mask_radius))
00259 return -1;
00260
00261
00262 av_picture_copy(s2, s1, PIX_FMT_GRAY8, newwidth, newheight);
00263 av_picture_copy(dst, s1, PIX_FMT_GRAY8, newwidth, newheight);
00264
00265
00266 rr2 = mask_radius + srcheight;
00267 cc2 = mask_radius + srcwidth;
00268 for (rr = mask_radius; rr < rr2; rr++)
00269 {
00270 for (cc = mask_radius; cc < cc2; cc++)
00271 {
00272 sum = 0;
00273 for (ii = -mask_radius; ii <= mask_radius; ii++)
00274 {
00275 sum += mask[ii + mask_radius] *
00276 s1->data[0][(rr + ii) * newwidth + cc];
00277 }
00278 s2->data[0][rr * newwidth + cc] = (unsigned char)(sum + 0.5);
00279 }
00280 }
00281
00282
00283 for (rr = mask_radius; rr < rr2; rr++)
00284 {
00285 for (cc = mask_radius; cc < cc2; cc++)
00286 {
00287 sum = 0;
00288 for (ii = -mask_radius; ii <= mask_radius; ii++)
00289 {
00290 sum += mask[ii + mask_radius] *
00291 s2->data[0][rr * newwidth + cc + ii];
00292 }
00293 dst->data[0][rr * newwidth + cc] = (unsigned char)(sum + 0.5);
00294 }
00295 }
00296
00297 return 0;
00298 }
00299
00300