Skip to content

Instantly share code, notes, and snippets.

@oubiwann
Last active August 29, 2015 14:24
Show Gist options
  • Select an option

  • Save oubiwann/47a341090a41e75b84c9 to your computer and use it in GitHub Desktop.

Select an option

Save oubiwann/47a341090a41e75b84c9 to your computer and use it in GitHub Desktop.
Modification of FFMeg's doc/examples/scaling_video.c that scales a YUV image
OS := $(shell uname -s)
ifeq ($(OS),Linux)
LIBTOOL = libtool
endif
ifeq ($(OS),Darwin)
LIBTOOL = glibtool
endif
FILENAME = scale_image
# use pkg-config for getting CFLAGS and LDLIBS
FFMPEG_LIBS= libavformat \
libavcodec \
libswscale \
libavutil \
CFLAGS += -Wall -g
CFLAGS := $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CFLAGS)
LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS)
compile: fresh $(FILENAME).o $(FILENAME)
fresh:
$(LIBTOOL) --mode=compile --tag=CC gcc -g -O -c $(FILENAME).c
.phony: fresh all clean
all: $(OBJS) $(EXAMPLES)
clean:
rm $(FILENAME) $(FILENAME).{lo,o}
/*
* Copyright (c) 2012 Stefano Sabatini
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @file
* libswscale API use example.
* @example scaling_image.c
*/
/**
Dependencies: FFMpeg libraries must be installed on your system.
To build:
make
To run filled demo:
./doc/examples/scaling_video output.yuv 128x128
To run scaled input file:
./doc/examples/scaling_video input.yuv 128x128 output.yuv 2048x256
To check results:
ffplay -f rawvideo -pix_finput.yuv 128x128 mt yuv420p -video_size 128x128 output.yuv
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavutil/imgutils.h>
#include <libavutil/parseutils.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
static void fill_yuv_image(uint8_t *data[4], int linesize[4],
int width, int height) {
int x, y;
/* Y */
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
data[0][y * linesize[0] + x] = x + y;
/* Cb and Cr */
for (y = 0; y < height / 2; y++) {
for (x = 0; x < width / 2; x++) {
data[1][y * linesize[1] + x] = 128 + y;
data[2][y * linesize[2] + x] = 64 + x;
}
}
}
static void read_yuv_image(FILE *file, uint8_t *src_data[4], uint8_t *dst_data[4], int width, int height) {
if (file != NULL) {
fread(src_data[0], sizeof(char), width * height, file);
fread(src_data[1], sizeof(char), width/2 * height/2, file);
fread(src_data[2], sizeof(char), width/2 * height/2, file);
dst_data = src_data;
}
}
static void write_yuv_image(FILE *file, uint8_t *data[4], int bufsize) {
fwrite(data[0], 1, bufsize, file);
fwrite(data[1], 1, bufsize/4, file);
fwrite(data[2], 1, bufsize/4, file);
}
static void write_filled_yuv_image(FILE *file, uint8_t *data[4], int bufsize) {
fwrite(data[0], 1, bufsize, file);
}
static int scale_fill (int argc, char **argv) {
enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUV420P, dst_pix_fmt = AV_PIX_FMT_YUV420P;
uint8_t *src_data[4], *dst_data[4];
int src_linesize[4], dst_linesize[4];
int src_w = 320, src_h = 240, dst_w, dst_h;
const char *dst_size = NULL;
const char *dst_filename = NULL;
FILE *dst_file;
int dst_bufsize;
struct SwsContext *sws_ctx;
int ret;
dst_filename = argv[1];
dst_size = argv[2];
if (av_parse_video_size(&dst_w, &dst_h, dst_size) < 0) {
fprintf(stderr,
"Invalid destination size '%s', must be in the form WxH or a valid size abbreviation\n",
dst_size);
exit(1);
}
dst_file = fopen(dst_filename, "wb");
if (!dst_file) {
fprintf(stderr, "Could not open destination file %s\n", dst_filename);
exit(1);
}
/* create scaling context */
sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt,
dst_w, dst_h, dst_pix_fmt,
SWS_BILINEAR | SWS_ACCURATE_RND, NULL, NULL, NULL);
if (!sws_ctx) {
fprintf(stderr,
"Impossible to create scale context for the conversion "
"fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
ret = AVERROR(EINVAL);
goto end;
}
/* allocate source and destination image buffers */
if ((ret = av_image_alloc(src_data, src_linesize,
src_w, src_h, src_pix_fmt, 16)) < 0) {
fprintf(stderr, "Could not allocate source image\n");
goto end;
}
/* buffer is going to be written to rawvideo file, no alignment */
if ((ret = av_image_alloc(dst_data, dst_linesize,
dst_w, dst_h, dst_pix_fmt, 1)) < 0) {
fprintf(stderr, "Could not allocate destination image\n");
goto end;
}
dst_bufsize = ret;
fill_yuv_image(src_data, src_linesize, src_w, src_h);
/* convert to destination format */
sws_scale(sws_ctx, (const uint8_t * const*)src_data,
src_linesize, 0, src_h, dst_data, dst_linesize);
write_filled_yuv_image(dst_file, dst_data, dst_bufsize);
fprintf(stderr, "Scaling succeeded. Play the output file with the command:\n"
"~/Downloads/ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename);
end:
fclose(dst_file);
av_freep(&src_data[0]);
av_freep(&dst_data[0]);
sws_freeContext(sws_ctx);
return ret < 0;
}
static int scale_file (int argc, char **argv) {
const char *dst_size = NULL;
const char *src_size = NULL;
const char *dst_filename = NULL;
const char *src_filename = NULL;
FILE *dst_file;
FILE *src_file;
int dst_bufsize;
struct SwsContext *sws_ctx;
int ret;
AVFrame* src_frame = av_frame_alloc();
AVFrame* dst_frame = av_frame_alloc();
src_filename = argv[1];
src_size = argv[2];
dst_filename = argv[3];
dst_size = argv[4];
src_frame->format = AV_PIX_FMT_YUV420P;
if (av_parse_video_size(&src_frame->width, &src_frame->height, src_size) < 0) {
fprintf(stderr,
"Invalid source size '%s', must be in the form WxH or a valid size abbreviation\n",
src_size);
exit(1);
}
avpicture_fill((AVPicture*)src_frame, NULL, src_frame->format, src_frame->width, src_frame->height);
dst_frame->format = AV_PIX_FMT_YUV420P;
if (av_parse_video_size(&dst_frame->width, &dst_frame->height, dst_size) < 0) {
fprintf(stderr,
"Invalid destination size '%s', must be in the form WxH or a valid size abbreviation\n",
dst_size);
exit(1);
}
avpicture_fill((AVPicture*)dst_frame, NULL, dst_frame->format, dst_frame->width, dst_frame->height);
src_file = fopen(src_filename, "rb");
if (!src_file) {
fprintf(stderr, "Could not open source file %s\n", src_filename);
exit(1);
}
dst_file = fopen(dst_filename, "wb");
if (!dst_file) {
fprintf(stderr, "Could not open destination file %s\n", dst_filename);
exit(1);
}
/* create scaling context */
sws_ctx = sws_getContext(src_frame->width, src_frame->height, src_frame->format,
dst_frame->width, dst_frame->height, dst_frame->format,
SWS_BILINEAR, NULL, NULL, NULL);
if (!sws_ctx) {
fprintf(stderr,
"Impossible to create scale context for the conversion "
"fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
av_get_pix_fmt_name(src_frame->format), src_frame->width, src_frame->height,
av_get_pix_fmt_name(dst_frame->format), dst_frame->width, dst_frame->height);
ret = AVERROR(EINVAL);
goto end;
}
/* allocate source and destination image buffers */
if ((ret = av_image_alloc(src_frame->data, src_frame->linesize,
src_frame->width, src_frame->height,
src_frame->format, 16)) < 0) {
fprintf(stderr, "Could not allocate source image\n");
goto end;
}
/* buffer is going to be written to rawvideo file, no alignment */
if ((ret = av_image_alloc(dst_frame->data, dst_frame->linesize,
dst_frame->width, dst_frame->height,
dst_frame->format, 1)) < 0) {
fprintf(stderr, "Could not allocate destination image\n");
goto end;
}
dst_bufsize = dst_frame->width * dst_frame->height;
read_yuv_image(src_file, src_frame->data, dst_frame->data, src_frame->width, src_frame->height);
/* convert to destination format */
sws_scale(sws_ctx,
(const uint8_t * const*)src_frame->data, src_frame->linesize,
0, src_frame->height,
dst_frame->data, dst_frame->linesize);
write_yuv_image(dst_file, dst_frame->data, dst_bufsize);
fprintf(stderr, "Scaling succeeded. Play the output file with the command:\n"
"~/Downloads/ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
av_get_pix_fmt_name(dst_frame->format), dst_frame->width, dst_frame->height, dst_filename);
end:
fclose(src_file);
fclose(dst_file);
av_frame_unref(src_frame);
av_frame_unref(dst_frame);
sws_freeContext(sws_ctx);
return ret < 0;
}
int main(int argc, char **argv) {
av_register_all();
int ret;
if (argc == 3) {
ret = scale_fill(argc, argv);
} else if (argc == 5) {
ret = scale_file(argc, argv);
} else {
fprintf(stderr, "Usage: %s intput_file input_size output_file output_size\n"
"API example program to show how to scale an image with libswscale.\n"
"This program generates a series of pictures, rescales them to the given "
"output_size and saves them to an output file named output_file\n."
"\n", argv[0]);
exit(1);
}
return ret < 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment