PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ffmpeg, g++ und cygwin



SirLacy
16-11-2009, 08:55
Hallo zusammen,

ich möchte mich ein wenig in ffmpeg einarbeiten und habe mich zu diesem Zweck an das auf ffmpeg.org verlinkte Tutorial (http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html) gewagt. Das ganze mit cygwin und g++ unter Windows. Ffmpeg ist kompiliert und installiert, die Cpp-Datei aus dem Tutorial (avcodec_sample.cpp) habe ich wie folgt kompiliert:



g++ -o avcodec_sample.exe -Wall -lavutil -lavcodec -lavformat -lswscale -lz -lm avcodec_sample.cpp


Folgender Fehler tritt dann auf:



/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x50): undefined reference to `avcodec_decode_video(AVCodecContext*, AVFrame*, int*, unsigned char const*, int)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0xc9): undefined reference to `av_read_packet(AVFormatContext*, AVPacket*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x11f): undefined reference to `avcodec_decode_video(AVCodecContext*, AVFrame*, int*, unsigned char const*, int)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x255): undefined reference to `av_register_all()'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x284): undefined reference to `av_open_input_file(AVFormatContext**, char const*, AVInputFormat*, int, AVFormatParameters*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x29f): undefined reference to `av_find_stream_info(AVFormatContext*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x2d6): undefined reference to `dump_format(AVFormatContext*, int, char const*, int)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x347): undefined reference to `avcodec_find_decoder(CodecID)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x390): undefined reference to `avcodec_open(AVCodecContext*, AVCodec*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x3a5): undefined reference to `avcodec_alloc_frame()'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x3ad): undefined reference to `avcodec_alloc_frame()'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x3e2): undefined reference to `avpicture_get_size(int, int, int)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x421): undefined reference to `avpicture_fill(AVPicture*, unsigned char*, int, int, int)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x4ae): undefined reference to `sws_getContext(int, int, int, int, int, int, int, SwsFilter*, SwsFilter*, double*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x521): undefined reference to `sws_scale(SwsContext*, unsigned char**, int*, int, int, unsigned char**, int*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x577): undefined reference to `av_free(void*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x582): undefined reference to `av_free(void*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x58d): undefined reference to `avcodec_close(AVCodecContext*)'
/cygdrive/c/WINNT/profiles/user/LOKALE~1/Temp/ccT8J4Yf.o:avcodec_sample.cpp:(.text+0x598): undefined reference to `av_close_input_file(AVFormatContext*)'
collect2: ld returned 1 exit status


Und jetzt noch ein paar Informationen zusätzlich. Das hier ist die Cpp-Datei:



#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <stdio.h>
#include <stdlib.h>

bool GetNextFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx,
int videoStream, AVFrame *pFrame)
{
static AVPacket packet;
static int bytesRemaining=0;
static uint8_t *rawData;
static bool fFirstTime=true;
int bytesDecoded;
int frameFinished;

// First time we're called, set packet.data to NULL to indicate it
// doesn't have to be freed
if(fFirstTime)
{
fFirstTime=false;
packet.data=NULL;
}

// Decode packets until we have decoded a complete frame
while(true)
{
// Work on the current packet until we have decoded all of it
while(bytesRemaining > 0)
{
// Decode the next chunk of data
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame,
&frameFinished, rawData, bytesRemaining);

// Was there an error?
if(bytesDecoded < 0)
{
fprintf(stderr, "Error while decoding frame\n");
return false;
}

bytesRemaining-=bytesDecoded;
rawData+=bytesDecoded;

// Did we finish the current frame? Then we can return
if(frameFinished)
return true;
}

// Read the next packet, skipping all packets that aren't for this
// stream
do
{
// Free old packet
if(packet.data!=NULL)
av_free_packet(&packet);

// Read new packet
if(av_read_packet(pFormatCtx, &packet)<0)
goto loop_exit;
} while(packet.stream_index!=videoStream);

bytesRemaining=packet.size;
rawData=packet.data;
}

loop_exit:

// Decode the rest of the last frame
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
rawData, bytesRemaining);

// Free last packet
if(packet.data!=NULL)
av_free_packet(&packet);

return frameFinished!=0;
}

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;
int i, videoStream;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVFrame *pFrameRGB;
int numBytes;
uint8_t *buffer;
static struct SwsContext *img_convert_ctx;

// Register all formats and codecs
av_register_all();

// Open video file
if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
return -1; // Couldn't open file

// Retrieve stream information
if(av_find_stream_info(pFormatCtx)<0)
return -1; // Couldn't find stream information

// Dump information about file onto standard error
dump_format(pFormatCtx, 0, argv[1], false);

// Find the first video stream
videoStream=-1;
for(i=0; i<pFormatCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_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)
return -1; // Codec not found

// Inform the codec that we can handle truncated bitstreams -- i.e.,
// bitstreams where frame boundaries 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)
return -1; // Could not open codec

// Hack to correct wrong frame rates that seem to be generated by some
// codecs
// if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1)
// pCodecCtx->frame_rate_base=1000;

// 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=new 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 save first five frames to disk
i=0;
while(GetNextFrame(pFormatCtx, pCodecCtx, videoStream, pFrame))
{
//img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame,
// pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
if(img_convert_ctx == NULL) {
fprintf(stderr, "Error: Cannot initialize the conversion context.\n");
exit(1);
}
sws_scale(img_convert_ctx, ((AVPicture*)pFrame)->data, pFrame->linesize, 0, pCodecCtx->height, ((AVPicture *)pFrameRGB)->data, ((AVPicture *)pFrameRGB)->linesize);

// Save the frame to disk
if(++i<=5)
SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
}

// Free the RGB image
delete [] buffer;
av_free(pFrameRGB);

// Free the YUV frame
av_free(pFrame);

// Close the codec
avcodec_close(pCodecCtx);

// Close the video file
av_close_input_file(pFormatCtx);

return 0;
}


Das ist mein /usr/local-Verzeichnis:



+---bin
+---etc
+---include
| +---libavcodec
| | avcodec.h
| | opt.h
| | vdpau.h
| |
| +---libavdevice
| | avdevice.h
| |
| +---libavformat
| | avformat.h
| | avio.h
| | rtsp.h
| | rtspcodes.h
| |
| +---libavutil
| | adler32.h
| | avstring.h
| | avutil.h
| | base64.h
| | common.h
| | crc.h
| | fifo.h
| | intfloat_readwrite.h
| | log.h
| | lzo.h
| | mathematics.h
| | md5.h
| | mem.h
| | random.h
| | rational.h
| | sha1.h
| |
| \---libswscale
| swscale.h
|
\---lib
| libavcodec.a
| libavdevice.a
| libavformat.a
| libavutil.a
| libswscale.a
|
\---pkgconfig
libavcodec.pc
libavdevice.pc
libavformat.pc
libavutil.pc
libswscale.pc


Eigentlich müssten alle benötigten Libraries da sein. Den Library-Pfad mit -L händisch zu setzen habe ich auch schon probiert, hat aber nichts geändert. Ich bin dankbar für alle Vorschläge.

anda_skoa
16-11-2009, 13:51
Nachdem ffmpeg hier als statische Bibliotheken vorliegt, könnte das Ändern der Reihenfolge der Linkerdirektiven helfen.

Ich hatte mal einen Fall, wo das der Grund für Linkerfehler war. Dabei hatte ich quasi libmybase.a und libmynetwork.a (wobei diese hier Symbole aus libmybase braucht) und während es so klappt


-lmynetwork -lmybase


schlug es so fehl


-lmybase -lmynetwork


Ciao,
_

SirLacy
16-11-2009, 14:08
Danke für den Hinweis. Ich hatte vergessen, zu schreiben, dass ich das schon probiert hatte. :)

undefined
18-11-2009, 13:22
ld weist darauf hin das du versuchst shareds zu laden.
Verwende -static im Compiler aufruf.

SirLacy
18-11-2009, 14:06
Hallo, danke für den Tip, aber das war auch nicht der Fehler. Ich bin inzwischen auf MSVC++ umgestiegen, auch wenn das nicht die Lösung war, die ich anvisiert hatte. Aber jetzt klappt wenigstens schonmal das Kompilieren. ;)