[FFmpeg-devel] in-memory URL Protocol patch
alanzhuang(庄奇东)
alanzhuang at tencent.com
Sat Dec 15 07:28:22 CET 2012
Dear all,
In some cases, in-memory processing may be needed to avoid Random R/W on disks.
Here I implemented in-memory URL protocol, hope you accept it :)
inmem:<shmid>_<start_offset>_<size>.<extension>
Example:
inmem:753666_65536_1673216.mp4
1. Add the below in /libavformat/file.c:
/*
implement in-mem protocol alanzhuang at tencent.com<mailto:alanzhuang at tencent.com>
*/
#if CONFIG_INMEM_PROTOCOL && (!defined WIN32) && (!defined WIN64)
typedef struct InMemContext
{
const AVClass *class;
int shmid;
key_t shmkey; /* preserved for future use */
off_t start_offset;
size_t size; /* currently use start position with size */
off_t cur_start_offset;
size_t cur_size;
} InMemContext;
static const AVClass in_mem_class =
{
.class_name = "inmem",
.item_name = av_default_item_name,
/* .option = file_options, */
.version = LIBAVUTIL_VERSION_INT,
};
static int in_mem_read(URLContext *h, unsigned char *buf, int size)
{
/*av_log(NULL, AV_LOG_ERROR, "in_mem_read()\n");*/
InMemContext *c = h->priv_data;
if (c->shmid == -1)
return -1;
void *start = (void*)((char*)shmat(c->shmid, NULL, 0) + c->cur_start_offset);
/*av_log(NULL, AV_LOG_ERROR, "before_read()\n");
av_log(NULL, AV_LOG_ERROR, "start: %llu, read_size: %d\n", (unsigned long long) start, size);*/
int real_size = FFMIN(size, c->cur_size);
memcpy(buf, start, real_size);/* FFMIN(size, end - start)); */
/*av_log(NULL, AV_LOG_ERROR, "after_read()\n");*/
c->cur_start_offset += real_size;
/*av_log(NULL, AV_LOG_ERROR, "start: %llu, read_size: %d\n", (unsigned long long)(shmat(c->shmid, NULL, 0) + c->cur_start_offset), real_size);*/
c->cur_size -= real_size;
/*int r = read(fd, buf, size);*/
return real_size;
}
static int in_mem_write(URLContext *h, const unsigned char *buf, int size)
{
/*av_log(NULL, AV_LOG_ERROR, "in_mem_write()\n");*/
InMemContext *c = h->priv_data;
if (c->shmid == -1)
return -1;
void *start = (void*)((char*)shmat(c->shmid, NULL, 0) + c->cur_start_offset);
/*av_log(NULL, AV_LOG_ERROR, "start: %llu, write_size: %d\n", (unsigned long long) start, size);
int r = write(fd, buf, size);*/
int real_size = FFMIN(size, c->cur_size);
memcpy(start, buf, real_size);
/*av_log(NULL, AV_LOG_ERROR, "after_write()\n");*/
c->cur_start_offset += real_size;
/*av_log(NULL, AV_LOG_ERROR, "start: %llu, read_size: %d\n", (unsigned long long) c->start, real_size);*/
c->cur_size -= real_size;
return real_size;
}
static int in_mem_get_handle(URLContext *h)
{
InMemContext *c = h->priv_data;
av_log(NULL, AV_LOG_ERROR, "in_mem_get_handle()!!!\n");
return (intptr_t) c->start_offset;
}
static int in_mem_check(URLContext *h, int mask)
{
return 0;
}
static int in_mem_open(URLContext *h, const char *filename, int flags)
{
/* av_log(NULL, AV_LOG_ERROR, "in_mem_open(): %s\n", filename); */
InMemContext *c = h->priv_data;
int shmid;
off_t start_offset;
char *final_shm, *final_start, *final_size;
size_t size;
av_strstart(filename, "inmem:", &filename);
shmid = (int)strtol(filename, &final_shm, 10);
if(filename == final_shm)
{
shmid = -1;
}
start_offset = (off_t)strtoull(final_shm + 1, &final_start, 10);
if(final_shm + 1 == final_start) /* No digits found, or something like 10ab */
{
start_offset = 0;
}
size = (size_t)strtoull(final_start + 1, &final_size, 10);
if((final_start + 1 == final_size)) /* || *final_size)*/
{
size = 0;
}
c->shmid = shmid;
c->start_offset = start_offset;
c->cur_start_offset = start_offset;
c->size = size;
c->cur_size =size;
h->is_streamed = 0;
return 0;
}
/* XXX: streaming, do not support seek currently */
static int64_t in_mem_seek(URLContext *h, int64_t pos, int whence)
{
int64_t ret;
InMemContext *c = h->priv_data;
/* av_log(NULL, AV_LOG_ERROR, "try mem_seek: pos: %lld, whence: %d\n", pos, whence); */
if (whence == AVSEEK_SIZE)
{
ret = (int64_t)c->size;
return ret;
}
if (whence == SEEK_SET)
{
c->cur_start_offset = c->start_offset + pos;
c->cur_size = c->size - pos;
}
else if (whence == SEEK_END)
{
c->cur_start_offset = c->start_offset + c->size + pos;
c->cur_size = 0 - pos;
}
return (int64_t)c->cur_start_offset;
}
static int in_mem_close(URLContext *h)
{
InMemContext *c = h->priv_data;
void *p = shmat(c->shmid, NULL, 0);
return shmdt(p);
/*return shmctl(c->shmid, IPC_RMID, NULL);*/
}
URLProtocol ff_inmem_protocol =
{
.name = "inmem",
.url_open = in_mem_open,
.url_read = in_mem_read,
.url_write = in_mem_write,
.url_seek = in_mem_seek,
.url_close = in_mem_close,
.url_get_file_handle = in_mem_get_handle,
.url_check = in_mem_check,
.priv_data_size = sizeof(InMemContext),
};
#endif /* CONFIG_INMEM_PROTOCOL */
2. Add
OBJS-$(CONFIG_INMEM_PROTOCOL) += file.o
in /libavformat/Makefile ( # protocols I/O section)
3. Add
CONFIG_INMEM_PROTOCOL=yes
in /config.mak
Testing:
// works with the latest ffmpeg
// based on tutorial01.c
//
// This tutorial was written by Stephen Dranger (dranger at gmail.com<mailto:dranger at gmail.com>) and updated
// for ffmpeg version N-42806-gf4451d2 by Michael Penkov
// (misha.penkov at gmail.com<mailto:misha.penkov at gmail.com>).
//
// Code based on a tutorial by Martin Bohme (boehme at inb.uni-luebeckREMOVETHIS.de<mailto:boehme at inb.uni-luebeckREMOVETHIS.de>)
// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
// A small sample program that shows how to use libavformat and libavcodec to
// read video from a file.
//
// Use the Makefile to build all examples.
//
// Run using
//
// tutorial01 myvideofile.mpg
//
// to write the first five frames fr
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <fcntl.h>
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
FILE *pFile;
char szFilename[32];
int y;
// Open file
sprintf(szFilename, "frame%d.ppm", iFrame);
pFile = fopen(szFilename, "wb");
if (pFile == NULL)
return;
// Write header
fprintf(pFile, "P6\n%d %d\n255\n", width, height);
// Write pixel data
for (y = 0; y < height; y++)
fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile);
// Close file
fclose(pFile);
}
int main(int argc, char *argv[])
{
AVFormatContext *pFormatCtx = NULL;
int i, videoStream;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrame = NULL;
AVFrame *pFrameRGB = NULL;
AVPacket packet;
int frameFinished;
int numBytes;
uint8_t *buffer = NULL;
AVDictionary *optionsDict = NULL;
struct SwsContext *sws_ctx = NULL;
if (argc < 1)
{
printf("Please provide a movie file\n");
return -1;
}
//生成key
key_t key = ftok(".", 1002);
//创建共享内存段
int shmid = shmget(key, 1673218, IPC_CREAT | IPC_EXCL | 0600);
if (shmid < 0)perror("error"), exit(-1);
//挂接共享内存段
void *p = shmat(shmid, NULL, 0);
if (p == (void*) - 1)perror("error"), exit(-1);
printf("key: %ld; shmid: %d; Addr: %llu\n", key, shmid, (unsigned long long) p);
int fd;
char filename[64];
fd = open("/home/cheedoong/111.mpg", O_RDONLY, 0755);
int nread = read(fd, p, 1673218);
sprintf(filename, "inmem:%llu_%llu_%llu.mpg", shmid, 0 , nread);
printf("filename: %s read: %d bytes.\n", filename, nread);
close(fd);
char cmd[256];
sprintf(cmd, "ffmpeg -i %s", filename); /* -vcodec libx264 -acodec libfaac inmem_trans.avi */
printf("before get information of %s \n", filename);
system(cmd);
printf("after get information of %s \n", filename);
//-vcodec copy -acodec copy -f mpegts 111.ts
// Register all formats and codecs
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, filename, 0);
// Find the first video stream
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
if (videoStream == -1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL)
{
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, &optionsDict) < 0)
return -1; // Could not open codec
// Allocate video frame
pFrame = avcodec_alloc_frame();
// Allocate an AVFrame structure
pFrameRGB = avcodec_alloc_frame();
if (pFrameRGB == NULL)
return -1;
// Determine required buffer size and allocate buffer
numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
sws_ctx =
sws_getContext
(
pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
PIX_FMT_RGB24,
SWS_BILINEAR,
NULL,
NULL,
NULL
);
// Assign appropriate parts of buffer to image planes in pFrameRGB
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
// of AVPicture
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
// Read frames and save first five frames to disk
i = 0;
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
// Is this a packet from the video stream?
if (packet.stream_index == videoStream)
{
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,
&packet);
// Did we get a video frame?
if (frameFinished)
{
// Convert the image from its native format to RGB
sws_scale
(
sws_ctx,
(uint8_t const * const *)pFrame->data,
pFrame->linesize,
0,
pCodecCtx->height,
pFrameRGB->data,
pFrameRGB->linesize
);
// Save the frame to disk
if (++i <= 5)
SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height,
i);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}
// Free the RGB image
av_free(buffer);
av_free(pFrameRGB);
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
// Close the video file
avformat_close_input(&pFormatCtx);
return 0;
}
BR~
More information about the ffmpeg-devel
mailing list