Hi, I needed to encode BGR packed PPMs streamed in from a v4l2 device (that only supported 'BGR3' and not 'RGB3') in realtime. For that I made minor changes to 'ppmtoy4m' and added an extra command line parameter '-B'. If the parameter is specified, the input data is treated as BGR packed pixels instead of the more commonly used RGB pixels.
In my program, the streamed video is also used in an OpenGL context. BGR packed pixels are commonly used as OpenGL textures since the the GPU is usually tuned to process the pixels in BGRA format and hence there is less overhead of having to 'swizzle' the bytes. Just thought I'd provide the patch here, in case somebody else had a similar need. It's a patch to the 'ppmtoy4m' in 1.6.2. Cheers, Anoop Menon. <[EMAIL PROTECTED]>
--- ppmtoy4m.c 2002-04-16 10:10:14.000000000 -0600 +++ ppmtoy4m.new.c 2005-02-10 16:35:50.000000000 -0700 @@ -54,6 +54,7 @@ int ss_mode; int verbosity; int fdin; + int bgr; } cl_info_t; @@ -96,6 +97,7 @@ fprintf(stdout, " '%s' -> %s\n", ssm_id[i], ssm_description[i]); /* fprintf(stdout, " -R type subsampling filter type\n");*/ fprintf(stdout, " -v n verbosity (0,1,2) [1]\n"); + fprintf(stdout, " -B PPM image is packed with BGR pixels (default is RGB)\n"); } @@ -115,9 +117,10 @@ cl->repeatlast = 0; cl->ss_mode = SSM_420_JPEG; cl->verbosity = 1; + cl->bgr = 0; cl->fdin = 0; /* default to stdin */ - while ((c = getopt(argc, argv, "A:F:I:Lo:n:rS:v:h")) != -1) { + while ((c = getopt(argc, argv, "BA:F:I:Lo:n:rS:v:h")) != -1) { switch (c) { case 'A': if (y4m_parse_ratio(&(cl->aspect), optarg) != Y4M_OK) { @@ -145,6 +148,9 @@ case 'L': cl->interleave = 1; break; + case 'B': + cl->bgr = 1; + break; case 'o': if ((cl->offset = atoi(optarg)) < 0) mjpeg_error_exit1("Offset must be >= 0: '%s'", optarg); @@ -198,6 +204,8 @@ cl->framerate.n, cl->framerate.d); mjpeg_info(" pixel aspect ratio: %d:%d", cl->aspect.n, cl->aspect.d); + mjpeg_info(" pixel packing: %s", + cl->bgr?"BGR":"RGB"); mjpeg_info(" interlace: %s%s", mpeg_interlace_code_definition(cl->interlace), (cl->interlace == Y4M_ILACE_NONE) ? "" : @@ -307,7 +315,7 @@ uint8_t *buffers[], uint8_t *buffers2[], uint8_t *rowbuffer, - int width, int height) + int width, int height, int bgr) { int x, y; uint8_t *pixels; @@ -324,18 +332,34 @@ pixels = rowbuffer; if (y4m_read(fd, pixels, width * 3)) mjpeg_error_exit1("read error A y=%d", y); - for (x = 0; x < width; x++) { - *(R++) = *(pixels++); - *(G++) = *(pixels++); - *(B++) = *(pixels++); + if (bgr) { + for (x = 0; x < width; x++) { + *(B++) = *(pixels++); + *(G++) = *(pixels++); + *(R++) = *(pixels++); + } + } else { + for (x = 0; x < width; x++) { + *(R++) = *(pixels++); + *(G++) = *(pixels++); + *(B++) = *(pixels++); + } } pixels = rowbuffer; if (y4m_read(fd, pixels, width * 3)) mjpeg_error_exit1("read error B y=%d", y); - for (x = 0; x < width; x++) { - *(R2++) = *(pixels++); - *(G2++) = *(pixels++); - *(B2++) = *(pixels++); + if (bgr) { + for (x = 0; x < width; x++) { + *(B2++) = *(pixels++); + *(G2++) = *(pixels++); + *(R2++) = *(pixels++); + } + } else { + for (x = 0; x < width; x++) { + *(R2++) = *(pixels++); + *(G2++) = *(pixels++); + *(B2++) = *(pixels++); + } } } } @@ -346,7 +370,7 @@ void read_ppm_into_one_buffer(int fd, uint8_t *buffers[], uint8_t *rowbuffer, - int width, int height) + int width, int height, int bgr) { int x, y; uint8_t *pixels; @@ -357,10 +381,18 @@ for (y = 0; y < height; y++) { pixels = rowbuffer; y4m_read(fd, pixels, width * 3); - for (x = 0; x < width; x++) { - *(R++) = *(pixels++); - *(G++) = *(pixels++); - *(B++) = *(pixels++); + if (bgr) { + for (x = 0; x < width; x++) { + *(B++) = *(pixels++); + *(G++) = *(pixels++); + *(R++) = *(pixels++); + } + } else { + for (x = 0; x < width; x++) { + *(R++) = *(pixels++); + *(G++) = *(pixels++); + *(B++) = *(pixels++); + } } } } @@ -378,7 +410,7 @@ static int read_ppm_frame(int fd, ppm_info_t *ppm, uint8_t *buffers[], uint8_t *buffers2[], - int ilace, int ileave) + int ilace, int ileave, int bgr) { int width, height; static uint8_t *rowbuffer = NULL; @@ -414,17 +446,17 @@ if (ilace == Y4M_ILACE_TOP_FIRST) { /* 1st buff arg == top field == temporally first == "buffers" */ read_ppm_into_two_buffers(fd, buffers, buffers2, - rowbuffer, width, height); + rowbuffer, width, height, bgr); } else { /* bottom-field-first */ /* 1st buff art == top field == temporally second == "buffers2" */ read_ppm_into_two_buffers(fd, buffers2, buffers, - rowbuffer, width, height); + rowbuffer, width, height, bgr); } } else if ((ilace == Y4M_ILACE_NONE) || (!ileave)) { /* Not Interlaced, or Not Interleaved: --> read image into first buffer... */ - read_ppm_into_one_buffer(fd, buffers, rowbuffer, width, height); + read_ppm_into_one_buffer(fd, buffers, rowbuffer, width, height, bgr); if ((ilace != Y4M_ILACE_NONE) && (!ileave)) { /* ...Actually Interlaced: --> read the second image/field into second buffer */ @@ -437,7 +469,7 @@ if ( (ppm->width != width) || (ppm->height != height) ) mjpeg_error_exit1("One of these frames is not like the others!"); - read_ppm_into_one_buffer(fd, buffers2, rowbuffer, width, height); + read_ppm_into_one_buffer(fd, buffers2, rowbuffer, width, height, bgr); } } return 0; @@ -513,7 +545,7 @@ /* Read first PPM frame/field-pair, to get dimensions */ if (read_ppm_frame(cl.fdin, &ppm, buffers, buffers2, - cl.interlace, cl.interleave)) + cl.interlace, cl.interleave, cl.bgr)) mjpeg_error_exit1("Failed to read first frame."); /* Setup streaminfo and write output header */ @@ -530,7 +562,7 @@ /* ...but skip reading very first frame, already read prior to loop */ if (count > 0) { err = read_ppm_frame(cl.fdin, &ppm, buffers, buffers2, - cl.interlace, cl.interleave); + cl.interlace, cl.interleave, cl.bgr); if (err == 1) { /* clean input EOF */ if (cl.repeatlast) {