126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross/*
226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * Copyright (C) 2012 The Android Open Source Project
326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross *
426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * Licensed under the Apache License, Version 2.0 (the "License");
526a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * you may not use this file except in compliance with the License.
626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * You may obtain a copy of the License at
726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross *
826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross *      http://www.apache.org/licenses/LICENSE-2.0
926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross *
1026a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * Unless required by applicable law or agreed to in writing, software
1126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * distributed under the License is distributed on an "AS IS" BASIS,
1226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * See the License for the specific language governing permissions and
1426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross * limitations under the License.
1526a417f68526fee861bb527f1a4e3ed548979f93Colin Cross */
1626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
1726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross#include <errno.h>
1826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross#include <setjmp.h>
1926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross#include <stdio.h>
2026a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
2126a417f68526fee861bb527f1a4e3ed548979f93Colin Crossextern "C" {
2226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross#include "jpeglib.h"
2326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross}
2426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
2526a417f68526fee861bb527f1a4e3ed548979f93Colin Crossstatic inline uint8_t from565to8(uint16_t p, int start, int bits) {
2626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    uint8_t c = (p >> start) & ((1 << bits) - 1);
2726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    return (c << (8 - bits)) | (c >> (bits - (8 - bits)));
2826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross}
2926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
3026a417f68526fee861bb527f1a4e3ed548979f93Colin Crossstruct sf_jpeg_error_mgr {
3126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    struct jpeg_error_mgr jerr;
3226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jmp_buf longjmp_buffer;
3326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross};
3426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
3526a417f68526fee861bb527f1a4e3ed548979f93Colin Crossvoid sf_jpeg_error_exit(j_common_ptr cinfo) {
3626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    struct sf_jpeg_error_mgr *sf_err = (struct sf_jpeg_error_mgr *)cinfo->err;
3726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    longjmp(sf_err->longjmp_buffer, 0);
3826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross}
3926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
4026a417f68526fee861bb527f1a4e3ed548979f93Colin Crossint writeJpegFile(const char *filename, uint8_t *frame, int width, int height) {
4126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    struct sf_jpeg_error_mgr sf_err;
4226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    struct jpeg_compress_struct cinfo;
4326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    uint8_t row_data[width * 3];
4426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    JSAMPROW row_pointer = row_data;
4526a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    FILE *f;
4626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
4726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    f = fopen(filename, "w");
4826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    if (!f) {
4926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        return -errno;
5026a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    }
5126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
5226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    cinfo.err = jpeg_std_error(&sf_err.jerr);
5326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    sf_err.jerr.error_exit = sf_jpeg_error_exit;
5426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    if (setjmp(sf_err.longjmp_buffer)) {
5526a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        jpeg_destroy_compress(&cinfo);
5626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        fclose(f);
5726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        return -1;
5826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    }
5926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
6026a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jpeg_create_compress(&cinfo);
6126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jpeg_stdio_dest(&cinfo, f);
6226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
6326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    cinfo.image_width = width;
6426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    cinfo.image_height = height;
6526a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    cinfo.input_components = 3;
6626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    cinfo.in_color_space = JCS_RGB;
6726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
6826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jpeg_set_defaults(&cinfo);
6926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jpeg_set_quality(&cinfo, 80, TRUE);
7026a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
7126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jpeg_start_compress(&cinfo, TRUE);
7226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
7326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    for (int row = 0; row < height; row++) {
7426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        uint16_t *src = (uint16_t *)(frame + row * width * 2);
7526a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        uint8_t *dst = row_data;
7626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        for (int col = 0; col < width; col++) {
7726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross            dst[0] = from565to8(*src, 11, 5);
7826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross            dst[1] = from565to8(*src, 5, 6);
7926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross            dst[2] = from565to8(*src, 0, 5);
8026a417f68526fee861bb527f1a4e3ed548979f93Colin Cross            dst += 3;
8126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross            src++;
8226a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        }
8326a417f68526fee861bb527f1a4e3ed548979f93Colin Cross        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
8426a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    }
8526a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
8626a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jpeg_finish_compress(&cinfo);
8726a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    jpeg_destroy_compress(&cinfo);
8826a417f68526fee861bb527f1a4e3ed548979f93Colin Cross
8926a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    fclose(f);
9026a417f68526fee861bb527f1a4e3ed548979f93Colin Cross    return 0;
9126a417f68526fee861bb527f1a4e3ed548979f93Colin Cross}
92