|
主要是介绍原理,然后为了介绍一下ffmpeg解码显示的操作其实并不复杂
1. 首先打开一个framebuffer
2. 打开文件
3. 正常解封装文件
4. 解码文件
5. 将解码的yuv转成rgb
6. 如果需要缩放则缩放操作
7. 将rgb铺到framebuffer
改的ffmpeg的demo:
[AppleScript] 纯文本查看 复制代码 gcc -I. -Isrc/ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -I/root/multimedia/ffmpeg/compat/atomics/gcc -std=c11 -fomit-frame-pointer -pthread -g -Wdeclaration-after-statement -Wall -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes -Wempty-body -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign -O3 -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=format-security -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=return-type -Werror=vla -Wformat -fdiagnostics-color=auto -Wno-maybe-uninitialized -MMD -MF doc/examples/demuxing_decoding.d -MT doc/examples/demuxing_decoding.o -c -o doc/examples/demuxing_decoding.o src/doc/examples/demuxing_decoding.c
代码如下:
[AppleScript] 纯文本查看 复制代码 /*
* 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
* Demuxing and decoding example.
*
* Show how to use the libavformat and libavcodec API to demux and
* decode audio and video data.
* @example demuxing_decoding.c
*/
#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <errno.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
uint8_t *fb_addr;
unsigned int fb_size;
unsigned int fb_width = 0;
unsigned int fb_line_size = 0;
unsigned int fb_height = 0;
static AVFormatContext *fmt_ctx = NULL;
static AVCodecContext *video_dec_ctx = NULL;
static int width, height;
static enum AVPixelFormat pix_fmt;
static AVStream *video_stream = NULL;
static const char *src_filename = NULL;
static int video_stream_idx = -1;
static AVFrame *frame = NULL;
static AVFrame *out_frame = NULL;
static AVPacket pkt;
static int video_frame_count = 0;
static int test_init_fb(void)
{
int screen_fbd=0;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
char *env=NULL;
unsigned int *color_white;
if(!(env = getenv("FRAMEBUFFER"))) {
env = "/dev/fb0";
}
screen_fbd = open(env, O_RDWR);
if(screen_fbd < 0) {
printf("liuqi Error Opening FrameBuffer Device:%s\r\n", env);
return 0;
} else {
printf("Success Opening FrameBuffer Device:%s\r\n",env);
}
if(ioctl(screen_fbd, FBIOGET_FSCREENINFO, &fb_fix) == -1) {
printf("Error Reading Screen Info FSCREENINFO.\n");
close(screen_fbd);
return 0;
}
if(ioctl(screen_fbd, FBIOGET_VSCREENINFO, &fb_var) == -1) {
printf("Error Reading Screen Info VSCREENINFO.\n");
close(screen_fbd);
return 0;
}
fb_size = fb_var.yres * fb_var.xres * 4;
fb_addr = (uint8_t *)mmap(NULL, fb_size, PROT_READ|PROT_WRITE,MAP_SHARED, screen_fbd, 0);
fb_width = fb_var.xres;
fb_line_size = fb_fix.line_length;
fb_height = fb_var.yres;
if (!fb_addr)
exit(1);
free(color_white);
return 0;
}
/* Enable or disable frame reference counting. You are not supposed to support
* both paths in your application but pick the one most appropriate to your
* needs. Look for the use of refcount in this example to see what are the
* differences of API usage between them. */
static int refcount = 0;
static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
{
AVFrame *picture;
int ret;
picture = av_frame_alloc();
if (!picture)
return NULL;
picture->format = pix_fmt;
picture->width = width;
picture->height = height;
/* allocate the buffers for the frame data */
ret = av_frame_get_buffer(picture, 4);
if (ret < 0) {
fprintf(stderr, "Could not allocate frame data.\n");
exit(1);
}
return picture;
}
static int decode_packet(int *got_frame, int cached)
{
int ret = 0;
int decoded = pkt.size;
*got_frame = 0;
if (pkt.stream_index == video_stream_idx) {
/* decode video frame */
ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt);
if (ret < 0) {
fprintf(stderr, "Error decoding video frame (%s)\n", av_err2str(ret));
return ret;
}
if (*got_frame) {
if (frame->width != width || frame->height != height ||
frame->format != pix_fmt) {
/* To handle this change, one could call av_image_alloc again and
* decode the following frames into another rawvideo file. */
fprintf(stderr, "Error: Width, height and pixel format have to be "
"constant in a rawvideo file, but the width, height or "
"pixel format of the input video changed:\n"
"old: width = %d, height = %d, format = %s\n"
"new: width = %d, height = %d, format = %s\n",
width, height, av_get_pix_fmt_name(pix_fmt),
frame->width, frame->height,
av_get_pix_fmt_name(frame->format));
return -1;
}
struct SwsContext *sws_ctx;
sws_ctx = sws_getContext(width, height, pix_fmt,
tmp_frame->width, tmp_frame->height, AV_PIX_FMT_BGRA,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(sws_ctx, (const uint8_t * const *) frame->data,
frame->linesize,
0,
height,
tmp_frame->data,
tmp_frame->linesize);
sws_freeContext(sws_ctx);
usleep(30000);
unsigned char *p = tmp_frame->data[0];
unsigned char *a = fb_addr;
int i = 0;
for (i = 0; i < tmp_frame->height; i++) {
memcpy(a, p, tmp_frame->linesize[0]);
a += fb_line_size;
p += tmp_frame->linesize[0];
}
}
}
/* If we use frame reference counting, we own the data and need
* to de-reference it when we don't use it anymore */
if (*got_frame && refcount)
av_frame_unref(frame);
return decoded;
}
static int open_codec_context(int *stream_idx, AVCodecContext **dec_ctx, AVFormatContext *fmt_ctx, enum AVMediaType type)
{
int ret, stream_index;
AVStream *st;
AVCodec *dec = NULL;
AVDictionary *opts = NULL;
ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
if (ret < 0) {
fprintf(stderr, "Could not find %s stream in input file '%s'\n",
av_get_media_type_string(type), src_filename);
return ret;
} else {
stream_index = ret;
st = fmt_ctx->streams[stream_index];
/* find decoder for the stream */
dec = avcodec_find_decoder(st->codecpar->codec_id);
if (!dec) {
fprintf(stderr, "Failed to find %s codec\n",
av_get_media_type_string(type));
return AVERROR(EINVAL);
}
/* Allocate a codec context for the decoder */
*dec_ctx = avcodec_alloc_context3(dec);
if (!*dec_ctx) {
fprintf(stderr, "Failed to allocate the %s codec context\n",
av_get_media_type_string(type));
return AVERROR(ENOMEM);
}
/* Copy codec parameters from input stream to output codec context */
if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
av_get_media_type_string(type));
return ret;
}
/* Init the decoders, with or without reference counting */
av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
if ((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) {
fprintf(stderr, "Failed to open %s codec\n",
av_get_media_type_string(type));
return ret;
}
*stream_idx = stream_index;
}
return 0;
}
int main (int argc, char **argv)
{
int ret = 0, got_frame;
test_init_fb();
if (argc != 2 && argc != 3) {
fprintf(stderr, "usage: %s [-refcount] input_file video_output_file audio_output_file\n"
"API example program to show how to read frames from an input file.\n"
"This program reads frames from a file, decodes them, and writes decoded\n"
"video frames to a rawvideo file named video_output_file, and decoded\n"
"audio frames to a bbs.chinaffmpeg.com-孙悟空 file named audio_output_file.\n\n"
"If the -refcount option is specified, the program use the\n"
"reference counting frame system which allows keeping a copy of\n"
"the data for longer than one decode call.\n"
"\n", argv[0]);
exit(1);
}
if (argc == 5 && !strcmp(argv[1], "-refcount")) {
refcount = 1;
argv++;
}
src_filename = argv[1];
/* open input file, and allocate format context */
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open source file %s\n", src_filename);
exit(1);
}
/* retrieve stream information */
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(1);
}
if (open_codec_context(&video_stream_idx, &video_dec_ctx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
video_stream = fmt_ctx->streams[video_stream_idx];
/* allocate image where the decoded image will be put */
width = video_dec_ctx->width;
height = video_dec_ctx->height;
pix_fmt = video_dec_ctx->pix_fmt;
out_frame = alloc_picture(AV_PIX_FMT_BGRA, 1280, 720);
}
/* dump input information to stderr */
av_dump_format(fmt_ctx, 0, src_filename, 0);
if (!video_stream) {
fprintf(stderr, "Could not find audio or video stream in the input, aborting\n");
ret = 1;
goto end;
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate frame\n");
ret = AVERROR(ENOMEM);
goto end;
}
/* initialize packet, set data to NULL, let the demuxer fill it */
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
/* read frames from the file */
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
AVPacket orig_pkt = pkt;
do {
ret = decode_packet(&got_frame, 0);
if (ret < 0)
break;
pkt.data += ret;
pkt.size -= ret;
} while (pkt.size > 0);
av_packet_unref(&orig_pkt);
}
/* flush cached frames */
pkt.data = NULL;
pkt.size = 0;
do {
decode_packet(&got_frame, 1);
} while (got_frame);
printf("Demuxing succeeded.\n");
end:
avcodec_free_context(&video_dec_ctx);
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
return ret < 0;
}
代码搞定之后,编译之后,首先要设置Linux的环境,确定是可以使用framebuffer设备:
代码如下:
[C] 纯文本查看 复制代码 #include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
int main(int argc, char *argv[])
{
int screen_fbd=0;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
char *env=NULL;
if(!(env = getenv("FRAMEBUFFER")))
{
env = "/dev/fb0";
}
screen_fbd = open(env, O_RDWR);
if(screen_fbd < 0)
{
printf("Error Opening FrameBuffer Device:%s\r\n", env);
return 0;
}
else
{
printf("Success Opening FrameBuffer Device:%s\r\n",env);
}
if(ioctl(screen_fbd, FBIOGET_FSCREENINFO, &fb_fix) == -1)
{
printf("Error Reading Screen Info FSCREENINFO.\n");
close(screen_fbd);
return 0;
}
printf("fb_fix.id=\"%s\"\r\n",fb_fix.id);
printf("fb_fix.smem_start=%#x\r\n",fb_fix.smem_start);
printf("fb_fix.mem_len=%d\r\n",fb_fix.smem_len);
printf("fb_fix.type=%d\r\n",fb_fix.type);
printf("fb_fix.type_aux=%d\r\n",fb_fix.type_aux);
printf("fb_fix.visual=%d\r\n",fb_fix.visual);
printf("fb_fix.line_length=%d\r\n",fb_fix.line_length);
printf("fb_fix.mmio_start=%#x\r\n",fb_fix.mmio_start);
printf("fb_fix.mmio_len=%#x\r\n",fb_fix.mmio_len);
printf("fb_fix.accel=%d\r\n",fb_fix.accel);
printf("fb_fix.accel=%s\r\n", "bbs.chinaffmpeg.com 孙悟空");
printf("fb_fix.reserved[0]=%d\r\n",fb_fix.reserved[0]);
printf("fb_fix.reserved[1]=%d\r\n",fb_fix.reserved[1]);
printf("fb_fix.reserved[2]=%d\r\n",fb_fix.reserved[2]);
if(ioctl(screen_fbd, FBIOGET_VSCREENINFO, &fb_var) == -1)
{
printf("Error Reading Screen Info VSCREENINFO.\n");
close(screen_fbd);
return 0;
}
printf("fb_var.xres=%d\r\n",fb_var.xres);
printf("fb_var.yres=%d\r\n",fb_var.yres);
printf("fb_var.xres_virtual=%d\r\n",fb_var.xres_virtual);
printf("fb_var.yres_virtual=%d\r\n",fb_var.yres_virtual);
printf("fb_var.xoffset=%d\r\n",fb_var.xoffset);
printf("fb_var.yoffset=%d\r\n",fb_var.yoffset);
printf("fb_var.bits_per_pixel=%d\r\n",fb_var.bits_per_pixel);
printf("fb_var.grayscale=%d\r\n",fb_var.grayscale);
printf("fb_var.red=%#x\r\n",fb_var.red);
printf("fb_var.green=%#x\r\n",fb_var.green);
printf("fb_var.blue=%#x\r\n",fb_var.blue);
printf("fb_var.transp=%#x\r\n",fb_var.transp);
printf("fb_var.nonstd=%d\r\n",fb_var.nonstd);
printf("fb_var.activate=%d\r\n",fb_var.activate);
printf("fb_var.height=%d\r\n",fb_var.height);
printf("fb_var.width=%d\r\n",fb_var.width);
printf("fb_var.accel_flags=%d\r\n",fb_var.accel_flags);
printf("fb_var.pixclock=%d\r\n",fb_var.pixclock);
printf("fb_var.left_margin=%d\r\n",fb_var.left_margin);
printf("fb_var.right_margin=%d\r\n",fb_var.right_margin);
printf("fb_var.upper_margin=%d\r\n",fb_var.upper_margin);
printf("fb_var.lower_margin=%d\r\n",fb_var.lower_margin);
printf("fb_var.hsync_len=%d\r\n",fb_var.hsync_len);
printf("fb_var.vsync_len=%d\r\n",fb_var.vsync_len);
printf("fb_var.sync=%d\r\n",fb_var.sync);
printf("fb_var.vmode=%d\r\n",fb_var.vmode);
printf("fb_var.rotate=%d\r\n",fb_var.rotate);
printf("fb_var.reserved[0]=%d\r\n",fb_var.reserved[0]);
printf("fb_var.reserved[1]=%d\r\n",fb_var.reserved[1]);
printf("fb_var.reserved[2]=%d\r\n",fb_var.reserved[2]);
printf("fb_var.reserved[3]=%d\r\n",fb_var.reserved[3]);
printf("fb_var.reserved[4]=%d\r\n",fb_var.reserved[4]);
return 0;
}
跑之后的效果如下图:
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|