|
| 1 | +// tutorial01.c |
| 2 | +// Code based on a tutorial by Martin Bohme ([email protected]) |
| 3 | +// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1 |
| 4 | + |
| 5 | +// A small sample program that shows how to use libavformat and libavcodec to |
| 6 | +// read video from a file. |
| 7 | +// |
| 8 | +// Use |
| 9 | +// |
| 10 | +// gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lz |
| 11 | +// |
| 12 | +// to build (assuming libavformat and libavcodec are correctly installed |
| 13 | +// your system). |
| 14 | +// |
| 15 | +// Run using |
| 16 | +// |
| 17 | +// tutorial01 myvideofile.mpg |
| 18 | +// |
| 19 | +// to write the first five frames from "myvideofile.mpg" to disk in PPM |
| 20 | +// format. |
| 21 | + |
| 22 | +/* |
| 23 | +gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lswscale -lz -lavutil -lm -lpthread |
| 24 | +*/ |
| 25 | + |
| 26 | +#include "libavcodec/avcodec.h" |
| 27 | +#include "libavformat/avformat.h" |
| 28 | +#include "libswscale/swscale.h" |
| 29 | + |
| 30 | + |
| 31 | +#include <stdio.h> |
| 32 | + |
| 33 | +void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) { |
| 34 | + FILE *pFile; |
| 35 | + FILE *pFile2; |
| 36 | + char szFilename[32]; |
| 37 | + char szFilename2[32]; |
| 38 | + int x, y; |
| 39 | + |
| 40 | + // Open file |
| 41 | + sprintf(szFilename, "frame%d.ppm", iFrame); |
| 42 | + sprintf(szFilename2, "frame%d", iFrame); |
| 43 | + pFile=fopen(szFilename, "wb"); |
| 44 | + pFile2=fopen(szFilename2, "w"); |
| 45 | + if(pFile==NULL) |
| 46 | + return; |
| 47 | + if(pFile2==NULL) |
| 48 | + return; |
| 49 | + |
| 50 | + // Write header |
| 51 | + fprintf(pFile, "P6\n%d %d\n255\n", width, height); |
| 52 | + fprintf(pFile2, "raw data of frame 51\n"); |
| 53 | + |
| 54 | + // Write pixel data |
| 55 | + for(y=0; y<height; y++) { |
| 56 | + fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile); |
| 57 | + if(y > 10) continue; |
| 58 | + else { |
| 59 | + fprintf(pFile2, "%d\n", y); |
| 60 | + for(x=0; x<width; x++) { |
| 61 | + fprintf(pFile2, "%d ", *(pFrame->data[0]+y*pFrame->linesize[0]+x)); |
| 62 | + } |
| 63 | + fprintf(pFile2, "\n"); |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | +/* size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream ); */ |
| 68 | +/* |
| 69 | +ptr |
| 70 | +Pointer to the array of elements to be written. |
| 71 | +size |
| 72 | +Size in bytes of each element to be written. |
| 73 | +count |
| 74 | +Number of elements, each one with a size of size bytes. |
| 75 | +stream |
| 76 | +Pointer to a FILE object that specifies an output stream. |
| 77 | +*/ |
| 78 | + |
| 79 | + // Close file |
| 80 | + fclose(pFile); |
| 81 | + fclose(pFile2); |
| 82 | +} |
| 83 | + |
| 84 | +int main(int argc, char *argv[]) { |
| 85 | + AVFormatContext *pFormatCtx; |
| 86 | + int i, videoStream; |
| 87 | + AVCodecContext *pCodecCtx; |
| 88 | + AVCodec *pCodec; |
| 89 | + AVFrame *pFrame; |
| 90 | + AVFrame *pFrameRGB; |
| 91 | + AVPacket packet; |
| 92 | + int frameFinished; |
| 93 | + int numBytes; |
| 94 | + uint8_t *buffer; |
| 95 | + static struct SwsContext *img_convert_ctx; |
| 96 | + |
| 97 | + if(argc < 2) { |
| 98 | + printf("Please provide a movie file\n"); |
| 99 | + return -1; |
| 100 | + } |
| 101 | + // Register all formats and codecs |
| 102 | + av_register_all(); |
| 103 | + |
| 104 | + // Open video file |
| 105 | + if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0) |
| 106 | + return -1; // Couldn't open file |
| 107 | + |
| 108 | + // Retrieve stream information |
| 109 | + if(av_find_stream_info(pFormatCtx)<0) |
| 110 | + return -1; // Couldn't find stream information |
| 111 | + |
| 112 | + // Dump information about file onto standard error |
| 113 | + dump_format(pFormatCtx, 0, argv[1], 0); |
| 114 | + |
| 115 | + // Find the first video stream |
| 116 | + videoStream=-1; |
| 117 | + for(i=0; i<pFormatCtx->nb_streams; i++) |
| 118 | + if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) { |
| 119 | + videoStream=i; |
| 120 | + break; |
| 121 | + } |
| 122 | + if(videoStream==-1) |
| 123 | + return -1; // Didn't find a video stream |
| 124 | + |
| 125 | + // Get a pointer to the codec context for the video stream |
| 126 | + pCodecCtx=pFormatCtx->streams[videoStream]->codec; |
| 127 | + |
| 128 | + // Find the decoder for the video stream |
| 129 | + pCodec=avcodec_find_decoder(pCodecCtx->codec_id); |
| 130 | + if(pCodec==NULL) { |
| 131 | + fprintf(stderr, "Unsupported codec!\n"); |
| 132 | + return -1; // Codec not found |
| 133 | + } |
| 134 | + // Open codec |
| 135 | + if(avcodec_open(pCodecCtx, pCodec)<0) |
| 136 | + return -1; // Could not open codec |
| 137 | + |
| 138 | + // Allocate video frame |
| 139 | + pFrame=avcodec_alloc_frame(); |
| 140 | + |
| 141 | + // Allocate an AVFrame structure |
| 142 | + pFrameRGB=avcodec_alloc_frame(); |
| 143 | + if(pFrameRGB==NULL) |
| 144 | + return -1; |
| 145 | + |
| 146 | + // Determine required buffer size and allocate buffer |
| 147 | + numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, |
| 148 | + pCodecCtx->height); |
| 149 | + buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); |
| 150 | + |
| 151 | + // Assign appropriate parts of buffer to image planes in pFrameRGB |
| 152 | + // Note that pFrameRGB is an AVFrame, but AVFrame is a superset |
| 153 | + // of AVPicture |
| 154 | + avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, |
| 155 | + pCodecCtx->width, pCodecCtx->height); |
| 156 | + |
| 157 | + // Read frames and save first five frames to disk |
| 158 | + i=0; |
| 159 | + while(av_read_frame(pFormatCtx, &packet)>=0) { |
| 160 | + // Is this a packet from the video stream? |
| 161 | + if(packet.stream_index==videoStream) { |
| 162 | + // Decode video frame |
| 163 | + avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, |
| 164 | + &packet); |
| 165 | + |
| 166 | + // Did we get a video frame? |
| 167 | + if(frameFinished) { |
| 168 | + /* |
| 169 | + // Convert the image from its native format to RGB |
| 170 | + img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, |
| 171 | + (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, |
| 172 | + pCodecCtx->height); |
| 173 | + */ |
| 174 | + img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, |
| 175 | + pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, |
| 176 | + PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); |
| 177 | + |
| 178 | + sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, |
| 179 | + 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); |
| 180 | + |
| 181 | + // Save the frame to disk |
| 182 | + ++i; |
| 183 | + if(i>50) |
| 184 | + if(i<=51) |
| 185 | + printf( "%d\n", *(pFrameRGB->data[0]) ); |
| 186 | + //SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i); |
| 187 | + } |
| 188 | + } |
| 189 | + |
| 190 | + // Free the packet that was allocated by av_read_frame |
| 191 | + av_free_packet(&packet); |
| 192 | + } |
| 193 | + |
| 194 | + // Free the RGB image |
| 195 | + av_free(buffer); |
| 196 | + av_free(pFrameRGB); |
| 197 | + |
| 198 | + // Free the YUV frame |
| 199 | + av_free(pFrame); |
| 200 | + |
| 201 | + // Close the codec |
| 202 | + avcodec_close(pCodecCtx); |
| 203 | + |
| 204 | + // Close the video file |
| 205 | + av_close_input_file(pFormatCtx); |
| 206 | + |
| 207 | + return 0; |
| 208 | +} |
0 commit comments