🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

2945閲覧

Segmentation faultで停止してしまうので困っています

Kitano

総合スコア15

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/12/21 17:56

編集2019/12/22 04:34

ネット上で拾ってきて少し手を入れたコードなのですが、コンパイルは問題無く通り実行することは出来るのですがセグメンテーションエラーで停止してしまいます。memmoveの引数のbuf.bytesusedが大きすぎてコピー範囲が範囲外になってしまっているようなのですがそうなる原因が一向に分からず困っております。
下記が該当のソースコードになります。
実行環境はRasPi4 Raspbian September2019 gccは8です。
またsshで接続して実行しています。

C++

1#include <stdint.h> 2#include <stdio.h> 3#include <stdlib.h> 4#include <string.h> 5#include <unistd.h> 6#include <sys/errno.h> 7#include <sys/fcntl.h> 8#include <sys/ioctl.h> 9#include <sys/mman.h> 10#include <linux/videodev2.h> 11 12int startCapture(); 13void copyBuffer(uint8_t *dstBuffer, uint32_t *size); 14void stopCapture(); 15int saveFileBinary(const char* filename, uint8_t* data, int size); 16 17int main() 18{ 19 uint8_t* buff = new uint8_t[320*240]; 20 uint32_t size; 21 if(startCapture() == -1) return 0; 22 copyBuffer(buff, &size); 23 printf("staer\n"); 24 stopCapture(); 25 saveFileBinary("aaa.jpg", buff, size); 26 delete[] buff; 27 return 0; 28} 29 30 31int fd; 32const int v4l2BufferNum = 2; 33void *v4l2Buffer[v4l2BufferNum]; 34uint32_t v4l2BufferSize[v4l2BufferNum]; 35 36int startCapture() 37{ 38 fd = open("/dev/video0", O_RDWR); 39 if(fd == -1){ 40 fprintf(stderr, "Device open failed\n"); 41 return(-1); 42 } 43 /* 1. フォーマット指定。320 x 240のJPEG形式でキャプチャしてください */ 44 struct v4l2_format fmt; 45 memset(&fmt, 0, sizeof(fmt)); 46 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 47 fmt.fmt.pix.width = 320; 48 fmt.fmt.pix.height = 240; 49 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; 50 ioctl(fd, VIDIOC_S_FMT, &fmt); 51 52 /* 2. バッファリクエスト。バッファを2面確保してください */ 53 struct v4l2_requestbuffers req; 54 memset(&req, 0, sizeof(req)); 55 req.count = v4l2BufferNum; 56 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 57 req.memory = V4L2_MEMORY_MMAP; 58 ioctl(fd, VIDIOC_REQBUFS, &req); 59 60 /* 3. 確保されたバッファをユーザプログラムからアクセスできるようにmmapする */ 61 struct v4l2_buffer buf; 62 for (uint32_t i = 0; i < v4l2BufferNum; i++) { 63 /* 3.1 確保したバッファ情報を教えてください */ 64 memset(&buf, 0, sizeof(buf)); 65 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 66 buf.memory = V4L2_MEMORY_MMAP; 67 buf.index = i; 68 ioctl(fd, VIDIOC_QUERYBUF, &buf); 69 70 /* 3.2 取得したバッファ情報を基にmmapして、後でアクセスできるようにアドレスを保持っておく */ 71 v4l2Buffer[i] = mmap(NULL, buf.length, PROT_READ, MAP_SHARED, fd, buf.m.offset); 72 v4l2BufferSize[i] = buf.length; 73 } 74 75 /* 4. バッファのエンキュー。指定するバッファをキャプチャするときに使ってください */ 76 for (uint32_t i = 0; i < v4l2BufferNum; i++) { 77 memset(&buf, 0, sizeof(buf)); 78 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 79 buf.memory = V4L2_MEMORY_MMAP; 80 buf.index = i; 81 ioctl(fd, VIDIOC_QBUF, &buf); 82 } 83 84 /* 5. ストリーミング開始。キャプチャを開始してください */ 85 enum v4l2_buf_type type; 86 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 87 ioctl(fd, VIDIOC_STREAMON, &type); 88 89 /* この例だと2面しかないので、2フレームのキャプチャ(1/30*2秒?)が終わった後、新たにバッファがエンキューされるまでバッファへの書き込みは行われない */ 90 return(0); 91} 92 93void copyBuffer(uint8_t *dstBuffer, uint32_t *size) 94{ 95 fd_set fds; 96 FD_ZERO(&fds); 97 FD_SET(fd, &fds); 98 99 /* 6. バッファに画データが書き込まれるまで待つ */ 100 while(select(fd + 1, &fds, NULL, NULL, NULL) < 0); 101 102 if (FD_ISSET(fd, &fds)) { 103 /* 7. バッファのデキュー。もっとも古くキャプチャされたバッファをデキューして、そのインデックス番号を教えてください */ 104 struct v4l2_buffer buf; 105 memset(&buf, 0, sizeof(buf)); 106 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 107 buf.memory = V4L2_MEMORY_MMAP; 108 ioctl(fd, VIDIOC_DQBUF, &buf); 109 110 /* 8. デキューされたバッファのインデックス(buf.index)と書き込まれたサイズ(buf.byteused)が返ってくる */ 111 *size = buf.bytesused; 112 113 /* 9. ユーザプログラムで使いやすいように、別途バッファにコピーしておく */ 114 memmove(dstBuffer, v4l2Buffer[buf.index], buf.bytesused); 115 116 /* 10. 先ほどデキューしたバッファを、再度エンキューする。カメラデバイスはこのバッファに対して再びキャプチャした画を書き込む */ 117 ioctl(fd, VIDIOC_QBUF, &buf); 118 } 119} 120 121void stopCapture() 122{ 123 /* 11. ストリーミング終了。キャプチャを停止してください */ 124 enum v4l2_buf_type type; 125 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 126 ioctl(fd, VIDIOC_STREAMOFF, &type); 127 128 /* 12. リソース解放 */ 129 for (uint32_t i = 0; i < v4l2BufferNum; i++) munmap(v4l2Buffer[i], v4l2BufferSize[i]); 130 131 /* 13. デバイスファイルを閉じる */ 132 close(fd); 133} 134 135int saveFileBinary(const char* filename, uint8_t* data, int size) 136{ 137 FILE *fp; 138 fp = fopen(filename, "wb"); 139 if(fp == NULL) { 140 return -1; 141 } 142 fwrite(data, sizeof(uint8_t), size, fp); 143 fclose(fp); 144 return 0; 145}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2019/12/22 00:38

> ネット上で拾ってきて少し手を入れたコード デバッグを他人に丸投げしようというのなら、せめて原典を示して変更箇所がわかるようにしていただきたいと思うのですが。あなたが手を入れたことで動かなくなった疑いが濃厚なのですから。
Kitano

2019/12/22 02:53

すみません 言われてみればその通りです。 こちらで変更した箇所はstartCapture関数内の if(fd == -1){ fprintf(stderr, "Device open failed\n"); return(-1); の追加とmemcpyからmemmoveへの変更です。 memcpyでも同様のエラーが出ており、コピー領域の被りが原因であるなら変更で動くようなので試しにmemmoveに変更してみましたが変わりありませんでした。
majiponi

2019/12/22 04:01

画面は8bit、グレースケールのものですか? それとも24bitフルカラーのものですか?
Kitano

2019/12/22 04:35

実行環境にはsshで接続して実行しており画面は繋がっていません。 またカメラはwebカメを使っています。
guest

回答1

0

自己解決

memmoveの書き込み先のバッファサイズがコピーバイト数の半分しか無いのが原因でした。
なぜこのような事になっていたのかが謎ですがとりあえず動作しました。
分かってしまえば簡単なことでした。
相談に乗っていただいた方々ありがとうございました。

投稿2019/12/22 05:04

Kitano

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問