Pointer assignment question

I am missing something here. Why can't I assign the address of a pointer to another pointer. Assign the dereferenced values work but not assigning pointer to pointer. I would have thought that assigning the value of q to p would make p point to the memory address pointed to by q and that this change would persist after decode function completes.

Thanks
Chris

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <cstdlib>
#include <iostream>

using namespace std;

/*
 * 
 */
void decode(int *p) {
    int *q = new int(5);
    std::cout << " q " << *q << std::endl;
    //p=q;  //does not work
    *p=*q; //works
}
int main(int argc, char** argv) {
    int *r,z;
    z=4;
    r=&z;
    std::cout << " r " << *r << std::endl;
    decode(r);
    std::cout << " r " << *r << std::endl;
    return 0;
}
Last edited on
I would have thought that assigning the value of q to p would make p point to the memory address pointed to by q
Yes.

that this change would persist after decode function completes
No. The [pointer] value of p is just a copy. Modifing p will change this copy without any effect to the caller. Only modifing the object pointed to will have an effect outside the called function.

So if you want to modify the pointer you have to either pass it as a reference or a pointer to the pointer (effectively the same):
1
2
3
4
5
6
void decode(int *&p) { // Note: & (reference)
    int *q = new int(5);
    std::cout << " q " << *q << std::endl;
    p=q;  //does work now
    //*p=*q; //works
}
Though, i would suggest to return the pointer to the newly created object.
Those kind of errors occur a lot when using pointers, when you do it it's important to stay focused and know exactly what you do. Otherwise, segmentation fault or other errors might pop. If those errors get too hard to be detected for you, there are programs that helps doing that, such as checkamrx and others you can use.
Good luck!
Ben.
Thanks a lot guys. My goal is to find a mechanism in which I could pass a pointer as argument to a function, get that pointer to steal the resource pointed by a pointer in that function that was allocated with malloc and have the dynamic memory allocated there survive the normal deallocation of the stolen from pointer. Here is the test code. Are there any memory leaks?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <cstdlib>
#include <iostream>

using namespace std;

/*
 * 
 */
void decode(int **p) {
    //int *q = new int(5);
    int *q=(int*)malloc(sizeof(int));
    *q=5;
    std::cout << " q " << *q << std::endl;
    *p=q;   //p is modifiable now because **p is the one copied by value
    q=nullptr;
    free(q);
    
}


int main(int argc, char** argv) {
    int *r,z;
    z=4;

    r=&z; 
    //Create a pointer to a pointer
    int **s=&r;
    std::cout << " r " << *r << std::endl;
    decode(s);
    std::cout << " r " << *r << std::endl;
    free(r);
    return 0;
}

Memory leaks? Probably. If *p (in line 14) points to dynamically allocated memory and nobody else points to it, then line 14 is a memory leak. In your example, the value r points to an integer on the stack, so the memory won't leak, but you can't count on that in the general case.

It can be a bit dangerous mixing pointers to statically (on the stack) and dynamically (on the heap) allocated variables. What type does r hold? In line 28, it's statically allocated. In line 31 it's dynamically allocated. How do you know whether or not to delete r when you are done.

You should look into smart pointers. Look at unique_ptr and shared_ptr. These template classes give you protection against memory leaks. However, I don't believe they are meant to be used as pointers to statically allocated objects. So they probably won't solve the problem in the previous paragraph.

Note on line 16 you free q which you just set to nullptr. That statement does nothing.

Since you are working in C++, you should start using new and delete rather than malloc and free. Statements 11-12 and 31 would then be:

int *q = new int(5);

delete r;

Also, consider @coder777's suggestion to use references to pointers. You still have an argument you can modify and the modifications persist back to the caller, but you also remove the complexity of always having to dereference the argument.
I am trying to modify ffmpeg's extract_mvs.c sample program in a way that I could extract the macroblock vectors efficiently and process them in a separate thread. The problem above is an analogue of extract_mvs.c. I have this sample code that seems to be working. sd in decode_packet is a sidedata pointer I believe created with malloc. I am trying to see if there is an efficient way of moving this data to another pointer that survives the destruction of sd by avframe_unref. Right now I am copying the sidedata to a an argument vector that is of length 1. Would it be possible to move this data to a AVFrameSideData pointer that I create and pass to decode_packet?

I am passing to decode_packet a pointer to a vector which essentially is a pointer to a pointer which is why it works I think (Pointer is copied by value but what it points to is modifiable).

This is probably full of errors that I don't realize.
Thanks,
Chris

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/motion_vector.h>
#include <libavformat/avformat.h>
}

#include <boost/circular_buffer.hpp>
#include <iostream>

static AVFormatContext *fmt_ctx = NULL;
static AVCodecContext *video_dec_ctx = NULL;
static AVStream *video_stream = NULL;
static const char *src_filename = NULL;

static int video_stream_idx = -1;
static AVFrame *frame = NULL;
static int video_frame_count = 0;

// Create a circular buffer with a capacity for 10 AVFrameSideData.
boost::circular_buffer<std::vector <AVFrameSideData> > cb(10);
std::vector<AVFrameSideData> mvects;



static int decode_packet(const AVPacket *pkt, std::vector<AVFrameSideData> *mvect)
{
    if (video_frame_count > 11)
            return -1;
    int ret = avcodec_send_packet(video_dec_ctx, pkt);
    if (ret < 0) {
        std::cout << "Error sending packet " << std::endl;
        return ret;
    }

    while (ret >= 0)  {
        ret = avcodec_receive_frame(video_dec_ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        } else if (ret < 0) {
            std::cout << "Error receiving packet" << std::endl;
            return ret;
        }
        
        
         
        if (ret >= 0) {
            int i;
            AVFrameSideData *sd;

            video_frame_count++;
            std::cout << "Frame count is " << video_frame_count << std::endl;
            sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
            if (sd) {
                *mvect = std::vector<AVFrameSideData>(sd,sd+1);
            } else
                mvect={};
            av_frame_unref(frame);
        }
    }

    return 0;
}

static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type)
{
    int ret;
    AVStream *st;
    AVCodecContext *dec_ctx = NULL;
    AVCodec *dec = NULL;
    AVDictionary *opts = NULL;

    ret = av_find_best_stream(fmt_ctx, type, -1, -1, &dec, 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 {
        int stream_idx = ret;
        st = fmt_ctx->streams[stream_idx];

        dec_ctx = avcodec_alloc_context3(dec);
        if (!dec_ctx) {
            fprintf(stderr, "Failed to allocate codec\n");
            return AVERROR(EINVAL);
        }

        ret = avcodec_parameters_to_context(dec_ctx, st->codecpar);
        if (ret < 0) {
            fprintf(stderr, "Failed to copy codec parameters to codec context\n");
            return ret;
        }

        /* Init the video decoder */
        av_dict_set(&opts, "flags2", "+export_mvs", 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;
        }

        video_stream_idx = stream_idx;
        video_stream = fmt_ctx->streams[video_stream_idx];
        video_dec_ctx = dec_ctx;
    }

    return 0;
}



int main(int argc, char **argv)
{
    int ret = 0;
    AVPacket pkt = { 0 };

    if (argc != 2) {
        fprintf(stderr, "Usage: %s rtsp://<user>:<pass>@url\n", argv[0]);
        exit(1);
    }
    src_filename = argv[1];
    avformat_network_init();
    

    av_register_all();

    if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open source %s\n", src_filename);
        exit(1);
    }

    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        exit(1);
    }

    open_codec_context(fmt_ctx, AVMEDIA_TYPE_VIDEO);

    av_dump_format(fmt_ctx, 0, src_filename, 0);

    if (!video_stream) {
        fprintf(stderr, "Could not find 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;
    }

    

    /* read frames from the file */
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == video_stream_idx) {
            ret = decode_packet(&pkt, &mvects);
                cb.push_back(mvects);
        }    
        av_packet_unref(&pkt);
        if (ret < 0)
            break;
    }
    

    for (auto j : cb) {
        
        std::vector<AVFrameSideData> mvlist=j;
        
        for (auto k : mvlist) {
            AVMotionVector *mv = (AVMotionVector*)k.data;
            int mvcount = k.size / sizeof(AVMotionVector);
            std::vector<AVMotionVector> mvlistv=std::vector<AVMotionVector>(mv,mv+mvcount);
            
            printf("Size MV %lu\n",mvlistv.size());
            std::cout << "Press Enter to Continue";
            std::cin.ignore();
            for (auto mv : mvlistv) {
            printf("%2d,%2d,%2d,%4d,%4d,%4d,%4d,0x%" PRIx64 "\n",
                        mv.source,
                        mv.w, mv.h, mv.src_x, mv.src_y,
                        mv.dst_x, mv.dst_y, mv.flags);
            }
        }

        
    }
    
    /* flush cached frames */
    //decode_packet(NULL,NULL);

end:
    avcodec_free_context(&video_dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&frame);
    return ret < 0;
}
Last edited on
Maybe somebody can comment on wether there are any memory leaks in this code.

I think this is what's happening.

There is a copy construction happening in line 215. There is a malloc line in line 103. There is only one buff variable initialized with nullptr on line 60 and it is being sent to decode_packet on line 213 where it receives a malloc address. After which it is passed to circular buffer as an rvalue and an object is created by move assignment and pushed into the circular buffer. A check for an allocated other.buf_data is done so the assignment wont result in a memory leak. The moved from rvalue copy is destroyed.

Until 10 ring_buffer objects are created, there should be no memory in the this.buf_data. After 10 ring_buffer objects are pushed into the circular buffer, further push_back into the circular buffer (causing an assigment operation where previous ring_buffer objects are assigned to) will result in the this.buf_data check to be non NULL and therefore the this.buf_data is freed.

I dont have to worry about the std::vector as its deallocation is automatic. At the end of the program, the program frees the uint8_t allocated pointer memory in each of the ring_buffer objects by calling the destructor ten times.
Thanks,
Chris
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
static AVFormatContext *fmt_ctx = NULL;
static AVCodecContext *video_dec_ctx = NULL;
static AVStream *video_stream = NULL;
static const char *src_filename = NULL;
AVCodecContext *dec_ctx = NULL;
AVCodec *dec = NULL;

static int video_stream_idx = -1;
static AVFrame *frame = NULL;
static int video_frame_count = 0;

class ring_buffer{
public:
    std::vector <AVFrameSideData> mv_data;
    uint8_t* buf_data;
    
    ring_buffer(std::vector <AVFrameSideData> imv_data, uint8_t* ibuf_data): mv_data(imv_data), buf_data(ibuf_data) { 
    }
    
    ring_buffer() {
        mv_data={};
        buf_data=nullptr;
    }
    
    ring_buffer( ring_buffer &&other){
        std::cout << "copy move constructor " <<std::endl;
       
        buf_data=other.buf_data;
        other.buf_data=nullptr;
        mv_data=other.mv_data;
        
    }
    
    
    ring_buffer& operator=( ring_buffer &&other){
        std::cout << "move assignment operator " <<std::endl;
        
        if (this!=&other) {
          if (buf_data)
                free(buf_data);
          buf_data=other.buf_data;
          other.buf_data=nullptr;
          mv_data=other.mv_data;
        }
        return *this;
    }
    
    ~ring_buffer(){
        std::cout << "Destructor" << std::endl;
        if (buf_data) {
            std::cout << "Freeing data" << std::endl;
            free(buf_data);
            buf_data=nullptr;
        }
    }
};
// Create a circular buffer with a capacity for 10 ring_buffer.
boost::circular_buffer<ring_buffer > cb(10);
std::vector<AVFrameSideData> mvects;
uint8_t* buff=nullptr;




static int decode_packet(const AVPacket *pkt, std::vector<AVFrameSideData> *mvect, uint8_t **buffer)
{
    if (video_frame_count > 500)
            return -1;
    std::cout << "FRAME " << video_frame_count << std::endl;
    
    //Start decode here
    int ret = avcodec_send_packet(video_dec_ctx, pkt);
    if (ret < 0) {
        std::cout << "Error sending packet " << std::endl;
        return ret;
    }

    while (ret >= 0)  {
        ret = avcodec_receive_frame(video_dec_ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        } else if (ret < 0) {
            std::cout << "Error receiving packet" << std::endl;
            return ret;
        }
        
        
        
         
        if (ret >= 0) {
            int i;
            AVFrameSideData *sd;

            video_frame_count++;
            sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
            if (sd) {
                *mvect = std::vector<AVFrameSideData>(sd,sd+1);
            } else
                mvect={};
  
            //SAVE the frame buffer to buffer in its default pixelformat
            int bufsize=av_image_get_buffer_size(AV_PIX_FMT_YUV420P, frame->width, frame->height, 1);
            *buffer = (uint8_t *) av_malloc(bufsize);
            ret=av_image_copy_to_buffer(*buffer, bufsize, (const uint8_t **)frame->data, frame->linesize,
                                AV_PIX_FMT_YUV420P, frame->width, frame->height, 1);
            
            if (ret<0)
                return ret;
            
            av_frame_unref(frame);
        }
    }

    return 0;
}

static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type)
{
    int ret;
    AVStream *st;
    
    AVDictionary *opts = NULL;

    ret = av_find_best_stream(fmt_ctx, type, -1, -1, &dec, 0);  //1 this version creates dec
    //ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); //2 this version requires avcodec_find_decoder
    
    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 {
        int stream_idx = ret;
        st = fmt_ctx->streams[stream_idx];
        //dec = avcodec_find_decoder(st->codecpar->codec_id); //2 
        
        dec_ctx = avcodec_alloc_context3(dec);
        if (!dec_ctx) {
            fprintf(stderr, "Failed to allocate codec\n");
            return AVERROR(EINVAL);
        }

        ret = avcodec_parameters_to_context(dec_ctx, st->codecpar);
        if (ret < 0) {
            fprintf(stderr, "Failed to copy codec parameters to codec context\n");
            return ret;
        }
        dec_ctx->pix_fmt=AV_PIX_FMT_YUV420P;

        /* Init the video decoder */
        av_dict_set(&opts, "flags2", "+export_mvs", 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;
        }

        video_stream_idx = stream_idx;
        video_stream = fmt_ctx->streams[video_stream_idx];
        video_dec_ctx = dec_ctx;
        
    }

    return 0;
}



int main(int argc, char **argv)
{
    int ret = 0;
    AVPacket pkt = { 0 };

    if (argc != 2) {
        fprintf(stderr, "Usage: %s rtsp://<user>:<pass>@url\n", argv[0]);
        exit(1);
    }
    src_filename = argv[1];
    avformat_network_init();
    

    av_register_all();

    if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open source %s\n", src_filename);
        exit(1);
    }

    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        exit(1);
    }

    open_codec_context(fmt_ctx, AVMEDIA_TYPE_VIDEO);

    av_dump_format(fmt_ctx, 0, src_filename, 0);

    if (!video_stream) {
        fprintf(stderr, "Could not find 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;
    }
    

    /* read frames from the file */
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == video_stream_idx) {
            ret = decode_packet(&pkt, &mvects, &buff);
            if (ret >= 0)
                cb.push_back(ring_buffer(mvects,buff));
            
        }    
        av_packet_unref(&pkt);
        if (ret < 0)
            break;
    }
    

    
    /* flush cached frames */
    //decode_packet(NULL,NULL);

end:
    avcodec_free_context(&video_dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&frame);
    return ret < 0;
}

	
Last edited on
Maybe somebody can comment on whether there are any memory leaks in this code.

A cursory look indicates that your code will leak resources if an exception is thrown while moving or constructing ring_buffer, thanks to its member std::vector<>. Line 97 has a similar problem.

I think your code would benefit greatly from consistent use of RAII. This would solve the above problem and shorten your program.

ring_buffer assumes that it takes ownership of buf_data.
To signal that to the caller, accept the pointer in the constructor by rvalue reference, or far more preferably, accept a rvalue reference to std::unique_ptr to enforce correct transfer of ownership.

Regarding the fact that these objects are not new'd and delete'd, the standard library supplies an interface for user-defined deleters and custom allocators, for the exact purpose of allowing the STL facilities to manage resources besides the obvious ones.
Last edited on

I have to read up on RAII and exception handling. The concepts are still confusing to me. Can you suggest a good tutorial link.

1. I think what you mean is that all allocations and deallocations need to be contained in a class object. That is av_malloc needs to be part of a buffer object constructor initialization to complement its counterpart free in destructor.

2. And that failure to allocate needs a mechanism to not change the this object in assignment.

Operating with malloc is pretty dangerous and leads to code bugs. If I move from a ring_buffer.buff_data pointer and take ownership of the buffer and forget to free, I get a leak. If the code that frees the buffer is skipped due to errors that force a function to return early or goto, leak. If I forget to free the buffer I assigned to an avframe that I constructed manually, leak.

Been watching the output of top to figure things out.

This is just a concept test anyway so I will forge on. I might redo with unique_ptr If I find that more and more bugs are creeping in.

If you have the time, can you suggest an implementation of a class object with unique_ptr handling the internal pointer dynamically allocated with av_malloc? Do I even need a custom object to hold the unique_ptr? If unique_ptr returns a pointer already, I could just replace all the malloc invocations with the unique_ptr invocations and forget about having to free the memory.


Thanks,
Chris

Last edited on
1. I think what you mean is that all allocations and deallocations need to be contained in a class object. That is av_malloc needs to be part of a buffer object constructor initialization to complement its counterpart free in destructor.

Yes, with one note: you don't need to actually perform the allocation inside the constructor (i.e., feel free to use dependency injection -- smart pointers do this), but you do need to make sure the object which manages the resource takes control of that resource before scope exit -- preferably sooner rather than later.

The idea behind the acronym RAII ("Resource Acquisition Is Initialization") is that acquiring a resource simultaneously creates (initializes) the object responsible for getting rid of it. The purpose of that is to ensure the resource gets released in the correct order by default, even in the presence of exceptions, which happens by tying the resource to an object that has a properly limited (usually automatic) storage duration lifetime.

2. And that failure to allocate needs a mechanism to not change the this object in assignment.

That mechanism often involves throwing an exception when resource allocation fails, as happens by default with new.

If you have the time, can you suggest an implementation of a class object with unique_ptr handling the internal pointer dynamically allocated with av_malloc?

You could directly use av_unique_ptr as follows:
1
2
3
4
5
6
7
8
9
10
11
12
struct av_deleter { 
  void operator()(AVCodecContext* const thing) const nothrow
  { ::avcodec_free_context(thing); }
  void operator()(AVFrame* const thing) const nothrow 
  { ::av_frame_free(thing); }
  void operator()(uint8_t* const thing) const nothrow 
  { ::free(thing); } 
  // more overloads for each resource type
};

template <typename T>
using av_unique_ptr = std::unique_ptr<T, av_deleter>;
Last edited on
I did not even think about writing a template and that's a great idea. I can wrap up all the deallocators to specific object pointers. I will try to integrate this in the code but it will take me some time due to other priorities. In the meantime, my original question was vexing me so I tried to come up with the solution. With regards to post #6 line 52:

1
2
3
4
5
           sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
            if (sd) {
                *mvect = std::vector<AVFrameSideData>(sd,sd+1);
            } else
                mvect={};


I changed it to the following which gets me there partially. The real solution would be to actually change the av_frame object such that the sideframedata is directly written into a supplied uint8_t buffer. Kinda like what is happening with the frame buffer data which is directly written to uint8_t buffer. libavcodec did have the function to set up the av_frame with a user supplied buffer but I cant find a function that does the same for sidedata.

1
2
3
4
5
6
7
8
9
 sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
            if (sd) {
                *mvect = (uint8_t *) av_malloc(sizeof(AVFrameSideData));
                memcpy(*mvect,sd,sizeof(AVFrameSideData));
                //std::cout << memcmp(*mvect,sd,sizeof(AVFrameSideData)) << std::endl;
                
            }
             else
                *mvect=nullptr;


And I think I made the appropriate changes to the ring_buffer class with regards to memory deallocation and moving. I think the code is mechanically sound, that is to say, there are no memory leaks and the program would run for hours without a problem or minutes and then segfault. Maybe you can spot something. The segfault seem to coincide with rtsp streaming problems so it might be a networking issue leading to invalid frames being received. Other than a check for a valid frame->buf[0] and using memset to fill the av_frame buffer with zeros prior to handling, I can't think of any other way to protect against a bad av_frame, but that is not really a cpp question.

The code is in github:
https://github.com/cmisip/h264_motion_vectors

Thanks,
Chris

Thanks for everyone's time and attention,

Chris
Topic archived. No new replies allowed.