avcodec_sample.c
/* avcodec_sample.c for ffmpeg 0.7.1
*
* @see http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html
* I read 'Using libavformat and libavcode'. but when use ffmpeg 0.7.1 on MAC OSX 10.7,
* the clang compiiler has some warning message. so I changed functions from deplicated
* to current.
*
* ChangeLog ********
* varialbes declaration like a Java.
* when error occured, write log by fprintf function.
* new/release(for C++) -> calloc/free(for C)
* use sowtware scaling library.
*
* make and run sample ********
* $ make
* clang -O2 -Wall -I/opt/local/include -I. -c avcodec_sample.c
* clang -Wall -L/opt/local/lib -L. -o avcodec_sample avcodec_sample.o -lavutil
-lavformat -lavcodec -lswscale -lz
* $ ./avcodec_sample mp4_h264_aac.mp4
*
* my tested environment ********
* Mac OSX 10.7
* XCode 4.1 (Apple clang compiler 2.1)
* ffmpe 0.7.1 (installed by Mac Ports)
*/
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "avcodec_sample.h"
void saveFrame(AVFrame *pFrame, int width, int height, int saveFrameCount) {
FILE *fp;
char szFilename[32];
sprintf(szFilename, "frame%d.ppm", saveFrameCount);
fp = fopen(szFilename, "wb");
if (fp == NULL) {
fprintf(stderr, "Couldn't open file for save.\n");
return;
}
/* Write PPM Header.
* P6 = Portable Pixcel Map (PPM)
* @see http://netpbm.sourceforge.net/doc/ppm.html
*/
fprintf(fp, "P6\n%d %d\n255\n", width, height);
for (int y = 0; y < height; y++) {
fwrite(pFrame->data[0]+y * pFrame->linesize[0], 1, width*3, fp);
}
fclose(fp);
}
int main(int argc, char *argv[]) {
// Registr all formats and codesc
av_register_all();
AVFormatContext *pFormatCtx = NULL;
const char *filename = argv[1];
// Open video file
// dplicated:av_open_input_file
// if (av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL) != 0) {
if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) {
fprintf(stderr, "Couldn't open file\n");
return -1;
}
// Retrieve stream infomation
if (av_find_stream_info(pFormatCtx) < 0) {
fprintf(stderr, "Couldn't find stream infomation\n");
return -1;
}
// Dump infomation about file onto standard error
// duplicated: dump_format
// dump_format(pFormatCtx, 0, filename, false);
av_dump_format(pFormatCtx, 0, filename, false);
// Find the first video stream
int videoStream = -1;
int streamLength = pFormatCtx->nb_streams;
for (int i = 0; i < streamLength; i++) {
if (CODEC_TYPE_VIDEO == pFormatCtx->streams[i]->codec->codec_type) {
videoStream = i;
break;
}
}
if (videoStream == -1) {
fprintf(stderr, "Didn't find a video stream\n");
return -1;
}
// Get apointer to the codec context for the video stream
AVCodecContext *pCodecCtx = pFormatCtx->streams[videoStream]->codec;
// Find the decoder for the video stream
AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL) {
fprintf(stderr, "Codec not found\n");
return -1;
}
// Inform the codec that we can handle truncated bitstreams -- i.e.,
// bitstreams where frame boundries can fall in the middle of packets
if (pCodec->capabilities & CODEC_CAP_TRUNCATED) {
pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
}
// Open codec
if (avcodec_open(pCodecCtx, pCodec) < 0) {
fprintf(stderr, "Couldn't open codec\n");
return -1;
}
// Hack to correct wrong frame rates that seem to be generated by some
// codes
//if (pCodecCtx->frame_rate > 1000 && pCodecCtx->frame_rate_base == 1) {
// pCodecCtx->frame_rate_base = 1000;
//}
// Allocate video frame
AVFrame *pFrame = avcodec_alloc_frame();
// Allocate an AVFrame structure
AVFrame *pFrameRGB = avcodec_alloc_frame();
if (pFrameRGB == NULL) {
fprintf(stderr, "Couldn't allocate frame memory\n");
return -1;
}
// Determin required buffer size and allocate buffer
int numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
/* changed from 'new' to 'calloc' for C language. */
// buffer = new uint8_t[[numBytes];
uint8_t *buffer = calloc(sizeof(uint8_t), numBytes);
// Assign appropriate parts of buffer to image planes in pFrameRGB
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
// read frames and first five frames to disk
AVPacket packet;
int frameFinished;
int saveFrameCount = 1;
static struct SwsContext *swsCtx; /* SWS means SoftWare Scaling */
/* packet is allocated in the av_read_frame function. */
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == videoStream) {
// duplicated
// avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished) {
/* Allocates and returns a SwsContext. */
swsCtx = sws_getCachedContext(swsCtx,
pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24,
SWS_BICUBIC,
NULL, /* source filter */
NULL, /* destination filter */
NULL);
sws_scale(swsCtx,
(const uint8_t *const *)pFrame->data,
pFrame->linesize,
0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
fprintf(stdout, ".");
// Save the frame to disk;
if (saveFrameCount <= 5) {
saveFrame(pFrameRGB,
pCodecCtx->width, pCodecCtx->height, saveFrameCount);
}
saveFrameCount++;
}
}
av_free_packet(&packet);
}
/* Free the SwsContext */
sws_freeContext(swsCtx);
// Free the RGB image
// delete [] buffer;
/* changed from 'delete' to 'free' for C language. */
free(buffer);
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
// Closes the video file
av_close_input_file(pFormatCtx);
return 0;
}
avcodec_sample.h
#ifndef __AVCODEC_SAMPLE__
#define __AVCODEC_SAMPLE__
#endif
Makefile
CC=clang
CFLAGS= -O2 -Wall
INCLUDES= -I/opt/local/include -I.
LDFLAGS= -Wall -L/opt/local/lib -L.
LIBS= -lavutil -lavformat -lavcodec -lswscale -lz
TARGET=avcodec_sample
OBJS=avcodec_sample.o
all:$(TARGET)
$(TARGET):$(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
clean:
-rm $(OBJS) $(TARGET) *.ppm
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $<
avcodec_sample.o:avcodec_sample.h