@@ -128,6 +128,16 @@ struct uvc_device {
128
128
struct k_poll_signal * sig ;
129
129
/** Byte offset within the currently transmitted video buffer */
130
130
size_t vbuf_offset ;
131
+ /** Current video buffer being filled */
132
+ struct video_buffer * current_vbuf ;
133
+ /** Expected frame ID for synchronization */
134
+ uint8_t expect_frame_id ;
135
+ /** Flag to discard first incomplete frame */
136
+ uint8_t discard_first_frame ;
137
+ /** Count of discarded frames */
138
+ uint32_t discard_frame_cnt ;
139
+ /** Number of transfers to prime initially */
140
+ uint8_t multi_prime_cnt ;
131
141
/** Number of completed transfers for current frame */
132
142
size_t transfer_count ;
133
143
/** USB camera control parameters */
@@ -2235,57 +2245,52 @@ static int uvc_host_remove_payload_header(struct net_buf *buf, struct video_buff
2235
2245
* @return 0 on success, negative error code on failure
2236
2246
*/
2237
2247
static int uvc_host_initiate_transfer (struct uvc_device * uvc_dev ,
2238
- struct video_buffer * const vbuf )
2248
+ struct video_buffer * const vbuf )
2239
2249
{
2240
- struct net_buf * buf ;
2241
- struct uhc_transfer * xfer ;
2242
- int ret ;
2243
-
2244
- /* Validate input parameters */
2245
- if (!vbuf || !uvc_dev || !uvc_dev -> current_stream_iface_info .current_stream_ep ) {
2246
- LOG_ERR ("Invalid parameters for transfer initiation" );
2247
- return - EINVAL ;
2248
- }
2249
-
2250
- LOG_DBG ("Initiating transfer: ep=0x%02x, vbuf=%p" ,
2251
- uvc_dev -> current_stream_iface_info .current_stream_ep -> bEndpointAddress , vbuf );
2252
-
2253
- /* Allocate USB transfer with callback */
2254
- xfer = usbh_xfer_alloc (uvc_dev -> udev , uvc_dev -> current_stream_iface_info .current_stream_ep -> bEndpointAddress ,
2255
- uvc_host_stream_iso_req_cb , uvc_dev );
2256
- if (!xfer ) {
2257
- LOG_ERR ("Failed to allocate transfer" );
2258
- return - ENOMEM ;
2259
- }
2260
-
2261
- /* Allocate transfer buffer with maximum packet size */
2262
- buf = usbh_xfer_buf_alloc (& uvc_dev -> udev , uvc_dev -> current_stream_iface_info .cur_ep_mps_mult );
2263
- if (!buf ) {
2264
- LOG_ERR ("Failed to allocate buffer" );
2265
- usbh_xfer_free (uvc_dev -> udev , xfer );
2266
- return - ENOMEM ;
2267
- }
2268
-
2269
- buf -> len = 0 ;
2270
-
2271
- /* Reset buffer offset and associate video buffer with transfer */
2272
- uvc_dev -> vbuf_offset = 0 ;
2273
- vbuf -> bytesused = 0 ;
2274
- memset (vbuf -> buffer , 0 , vbuf -> size );
2275
-
2276
- /* Save video buffer pointer in transfer's user data */
2277
- * (void * * )net_buf_user_data (buf ) = vbuf ;
2278
- xfer -> buf = buf ;
2279
-
2280
- ret = usbh_xfer_enqueue (uvc_dev -> udev , xfer );
2281
- if (ret != 0 ) {
2282
- LOG_ERR ("Enqueue failed: ret=%d" , ret );
2283
- net_buf_unref (buf );
2284
- usbh_xfer_free (uvc_dev -> udev , xfer );
2285
- return ret ;
2286
- }
2287
-
2288
- return 0 ;
2250
+ struct net_buf * buf ;
2251
+ struct uhc_transfer * xfer ;
2252
+ int ret ;
2253
+
2254
+ /* Validate input parameters */
2255
+ if (!vbuf || !uvc_dev || !uvc_dev -> current_stream_iface_info .current_stream_ep ) {
2256
+ LOG_ERR ("Invalid parameters for transfer initiation" );
2257
+ return - EINVAL ;
2258
+ }
2259
+
2260
+ LOG_DBG ("Initiating transfer: ep=0x%02x, vbuf=%p" ,
2261
+ uvc_dev -> current_stream_iface_info .current_stream_ep -> bEndpointAddress , vbuf );
2262
+
2263
+ /* Allocate USB transfer with callback */
2264
+ xfer = usbh_xfer_alloc (uvc_dev -> udev ,
2265
+ uvc_dev -> current_stream_iface_info .current_stream_ep -> bEndpointAddress ,
2266
+ uvc_host_stream_iso_req_cb , uvc_dev );
2267
+ if (!xfer ) {
2268
+ LOG_ERR ("Failed to allocate transfer" );
2269
+ return - ENOMEM ;
2270
+ }
2271
+
2272
+ /* Allocate transfer buffer with maximum packet size */
2273
+ buf = usbh_xfer_buf_alloc (& uvc_dev -> udev ,
2274
+ uvc_dev -> current_stream_iface_info .cur_ep_mps_mult );
2275
+ if (!buf ) {
2276
+ LOG_ERR ("Failed to allocate buffer" );
2277
+ usbh_xfer_free (uvc_dev -> udev , xfer );
2278
+ return - ENOMEM ;
2279
+ }
2280
+
2281
+ buf -> len = 0 ;
2282
+ uvc_dev -> vbuf_offset = 0 ;
2283
+ xfer -> buf = buf ;
2284
+
2285
+ ret = usbh_xfer_enqueue (uvc_dev -> udev , xfer );
2286
+ if (ret != 0 ) {
2287
+ LOG_ERR ("Enqueue failed: ret=%d" , ret );
2288
+ net_buf_unref (buf );
2289
+ usbh_xfer_free (uvc_dev -> udev , xfer );
2290
+ return ret ;
2291
+ }
2292
+
2293
+ return 0 ;
2289
2294
}
2290
2295
2291
2296
/**
@@ -2312,7 +2317,6 @@ static int uvc_host_continue_transfer(struct uvc_device *uvc_dev, struct uhc_tra
2312
2317
}
2313
2318
2314
2319
buf -> len = 0 ;
2315
- * (void * * )net_buf_user_data (buf ) = vbuf ;
2316
2320
xfer -> buf = buf ;
2317
2321
2318
2322
ret = usbh_xfer_enqueue (uvc_dev -> udev , xfer );
@@ -2330,6 +2334,7 @@ static int uvc_host_continue_transfer(struct uvc_device *uvc_dev, struct uhc_tra
2330
2334
*
2331
2335
* Handles completion of isochronous video data transfers. Processes
2332
2336
* received video data, removes UVC headers, and manages frame completion.
2337
+ * Only processes data with matching frame ID to ensure frame integrity.
2333
2338
*
2334
2339
* @param dev Pointer to USB device
2335
2340
* @param xfer Pointer to completed transfer
@@ -2339,10 +2344,15 @@ static int uvc_host_stream_iso_req_cb(struct usb_device *const dev, struct uhc_t
2339
2344
{
2340
2345
struct uvc_device * uvc_dev = (struct uvc_device * )xfer -> priv ;
2341
2346
struct net_buf * buf = xfer -> buf ;
2342
- struct video_buffer * vbuf = * ( struct video_buffer * * ) net_buf_user_data ( buf ) ;
2347
+ struct video_buffer * vbuf = uvc_dev -> current_vbuf ;
2343
2348
struct uvc_payload_header * payload_header ;
2349
+ uint32_t headLength ;
2350
+ uint32_t dataSize ;
2344
2351
uint8_t endOfFrame ;
2345
- uint32_t payload_len ;
2352
+ uint8_t frame_id ;
2353
+ uint32_t presentationTime ;
2354
+ static uint8_t s_savePicture = 0 ;
2355
+ static uint32_t s_currentFrameTimeStamp = 0 ;
2346
2356
2347
2357
/* Validate callback parameters */
2348
2358
if (!buf || !uvc_dev ) {
@@ -2353,62 +2363,126 @@ static int uvc_host_stream_iso_req_cb(struct usb_device *const dev, struct uhc_t
2353
2363
/* Handle transfer completion status */
2354
2364
if (xfer -> err == - ECONNRESET ) {
2355
2365
LOG_INF ("ISO transfer canceled" );
2366
+ goto cleanup ;
2356
2367
} else if (xfer -> err ) {
2357
2368
LOG_WRN ("ISO request failed, err %d" , xfer -> err );
2358
- } else {
2359
- LOG_DBG ("ISO request finished, len=%u" , buf -> len );
2369
+ goto cleanup ;
2360
2370
}
2361
2371
2362
- /* Process received video data if present */
2363
- if (buf -> len > 0 && vbuf )
2364
- {
2365
- /* Extract frame end marker from payload header */
2366
- payload_header = (struct uvc_payload_header * )buf -> data ;
2367
- endOfFrame = payload_header -> bmHeaderInfo & UVC_BMHEADERINFO_END_OF_FRAME ;
2368
- /* Remove UVC header and extract payload data */
2369
- payload_len = uvc_host_remove_payload_header (buf , vbuf );
2370
- if (payload_len < 0 ) {
2371
- LOG_ERR ("Header removal failed: %d" , payload_len );
2372
- goto cleanup ;
2373
- }
2374
-
2375
- /* Update video buffer with processed data */
2376
- vbuf -> bytesused += payload_len ;
2377
- uvc_dev -> vbuf_offset = vbuf -> bytesused ;
2378
-
2379
- LOG_DBG ("Processed %u payload bytes, total: %u, EOF: %u" ,
2380
- payload_len , vbuf -> bytesused , endOfFrame );
2381
-
2382
- /* Handle frame completion */
2383
- if (endOfFrame ) {
2384
- LOG_INF ("Frame completed: %u bytes" , vbuf -> bytesused );
2385
- /* Release network buffer reference */
2386
- net_buf_unref (buf );
2387
- /* Move completed buffer from input to output queue */
2388
- k_fifo_get (& uvc_dev -> fifo_in , K_NO_WAIT );
2389
- k_fifo_put (& uvc_dev -> fifo_out , vbuf );
2390
-
2391
- /* Clean up transfer resources */
2392
- uvc_dev -> vbuf_offset = 0 ;
2393
- usbh_xfer_free (dev , xfer );
2394
- uvc_dev -> transfer_count = 0 ;
2395
-
2396
- /* Signal frame completion to application */
2397
- LOG_DBG ("Raising VIDEO_BUF_DONE signal" );
2398
- k_poll_signal_raise (uvc_dev -> sig , VIDEO_BUF_DONE );
2399
- if ((vbuf = k_fifo_peek_head (& uvc_dev -> fifo_in )) != NULL ) {
2400
- vbuf -> bytesused = 0 ;
2401
- uvc_host_initiate_transfer (uvc_dev , vbuf );
2372
+ payload_header = (struct uvc_payload_header * )buf -> data ;
2373
+ endOfFrame = payload_header -> bmHeaderInfo & UVC_BMHEADERINFO_END_OF_FRAME ;
2374
+ frame_id = payload_header -> bmHeaderInfo & UVC_BMHEADERINFO_FRAMEID ;
2375
+ presentationTime = sys_le32_to_cpu (payload_header -> dwPresentationTime );
2376
+ headLength = payload_header -> bHeaderLength ;
2377
+
2378
+ if (buf -> len > 0 ) {
2379
+ /* the standard header is 12 bytes */
2380
+ if (buf -> len > 11 ) {
2381
+ dataSize = buf -> len - headLength ;
2382
+ /* there is payload for this transfer */
2383
+ if (dataSize ) {
2384
+ if (vbuf -> bytesused == 0U ) {
2385
+ if (s_currentFrameTimeStamp != presentationTime ) {
2386
+ s_currentFrameTimeStamp = presentationTime ;
2387
+ }
2388
+ }
2389
+ /* presentation time should be the same for the same frame, if not, discard this picture */
2390
+ else if (presentationTime != s_currentFrameTimeStamp ) {
2391
+ s_savePicture = 0 ;
2392
+ }
2393
+
2394
+ /* the current picture buffers are not available, now discard the receiving picture */
2395
+ if ((!vbuf && s_savePicture )) {
2396
+ s_savePicture = 0 ;
2397
+ } else if (s_savePicture ) {
2398
+ if (dataSize > (vbuf -> size - vbuf -> bytesused )) { /* error here */
2399
+ s_savePicture = 0 ;
2400
+ vbuf -> bytesused = 0U ;
2401
+ uvc_dev -> vbuf_offset = 0 ;
2402
+ } else {
2403
+ /* the same frame id indicates they belong to the same frame */
2404
+ if (frame_id == uvc_dev -> expect_frame_id ) {
2405
+ /* copy data to picture buffer */
2406
+ memcpy ((void * )(((uint8_t * )vbuf -> buffer ) + vbuf -> bytesused ),
2407
+ (void * )(((uint8_t * )buf -> data ) + headLength ),
2408
+ dataSize );
2409
+ vbuf -> bytesused += dataSize ;
2410
+ uvc_dev -> vbuf_offset = vbuf -> bytesused ;
2411
+
2412
+ LOG_DBG ("Processed %u payload bytes (FID:%u), total: %u, EOF: %u" ,
2413
+ dataSize , frame_id , vbuf -> bytesused , endOfFrame );
2414
+ } else {
2415
+ /* for the payload that has different frame id, discard it */
2416
+ s_savePicture = 0 ;
2417
+ LOG_DBG ("Frame ID mismatch: expected %u, got %u - discarding" ,
2418
+ uvc_dev -> expect_frame_id , frame_id );
2419
+ }
2420
+ }
2421
+ } else {
2422
+ /* no action */
2423
+ }
2424
+ }
2425
+
2426
+ if (s_savePicture ) {
2427
+ if (endOfFrame ) {
2428
+ if (vbuf -> bytesused != 0 ) {
2429
+ LOG_INF ("Frame completed: %u bytes (FID: %u)" ,
2430
+ vbuf -> bytesused , frame_id );
2431
+
2432
+ /* Move completed buffer from input to output queue */
2433
+ k_fifo_get (& uvc_dev -> fifo_in , K_NO_WAIT );
2434
+ k_fifo_put (& uvc_dev -> fifo_out , vbuf );
2435
+
2436
+ /* toggle the expected frame id */
2437
+ uvc_dev -> expect_frame_id = uvc_dev -> expect_frame_id ^ 1 ;
2438
+ s_savePicture = 1 ;
2439
+
2440
+ /* Clean up transfer resources */
2441
+ uvc_dev -> vbuf_offset = 0 ;
2442
+ uvc_dev -> transfer_count = 0 ;
2443
+
2444
+ /* Signal frame completion to application */
2445
+ LOG_DBG ("Raising VIDEO_BUF_DONE signal" );
2446
+ k_poll_signal_raise (uvc_dev -> sig , VIDEO_BUF_DONE );
2447
+
2448
+ /* switch to another buffer to save picture frame */
2449
+ if ((vbuf = k_fifo_peek_head (& uvc_dev -> fifo_in )) != NULL ) {
2450
+ vbuf -> bytesused = 0 ;
2451
+ memset (vbuf -> buffer , 0 , vbuf -> size );
2452
+ uvc_dev -> current_vbuf = vbuf ;
2453
+ }
2454
+ }
2455
+ }
2456
+ } else {
2457
+ /* the last frame of one picture */
2458
+ if (endOfFrame ) {
2459
+ if (uvc_dev -> discard_first_frame ) {
2460
+ uvc_dev -> discard_first_frame = 0 ;
2461
+ uvc_dev -> expect_frame_id = frame_id ^ 1 ;
2462
+ }
2463
+ if (vbuf && vbuf -> bytesused != 0 ) {
2464
+ uvc_dev -> discard_frame_cnt ++ ;
2465
+ }
2466
+ if (vbuf ) {
2467
+ vbuf -> bytesused = 0U ;
2468
+ uvc_dev -> vbuf_offset = 0 ;
2469
+ }
2470
+ if (!uvc_dev -> discard_first_frame ) {
2471
+ uvc_dev -> expect_frame_id = frame_id ^ 1 ;
2472
+ }
2473
+ s_savePicture = 1 ;
2474
+ }
2402
2475
}
2403
- return 0 ;
2404
2476
}
2405
2477
}
2406
2478
2407
2479
cleanup :
2408
2480
/* Release network buffer reference */
2409
2481
net_buf_unref (buf );
2410
2482
/* Continue processing pending buffers */
2411
- uvc_host_continue_transfer (uvc_dev , xfer , vbuf );
2483
+ if (vbuf ) {
2484
+ uvc_host_continue_transfer (uvc_dev , xfer , vbuf );
2485
+ }
2412
2486
return 0 ;
2413
2487
}
2414
2488
@@ -2742,7 +2816,6 @@ static int uvc_host_init(struct usbh_class_data *cdata)
2742
2816
uvc_dev -> vs_input_header = NULL ;
2743
2817
uvc_dev -> vs_output_header = NULL ;
2744
2818
2745
-
2746
2819
/** Initialize format information */
2747
2820
memset (& uvc_dev -> formats , 0 , sizeof (struct uvc_format_info_all ));
2748
2821
if (uvc_dev -> video_format_caps ) {
@@ -2753,6 +2826,12 @@ static int uvc_host_init(struct usbh_class_data *cdata)
2753
2826
/** Initialize current format information */
2754
2827
memset (& uvc_dev -> current_format , 0 , sizeof (struct uvc_format_info ));
2755
2828
2829
+ uvc_dev -> expect_frame_id = 0xFF ;
2830
+ /* dicard the first picture because the first picture may be not complete */
2831
+ uvc_dev -> discard_first_frame = 1 ;
2832
+ uvc_dev -> discard_frame_cnt = 0 ;
2833
+ uvc_dev -> multi_prime_cnt = CONFIG_USBH_VIDEO_MULTIPLE_PRIME_COUNT ;
2834
+
2756
2835
LOG_INF ("UVC device structure initialized successfully" );
2757
2836
return 0 ;
2758
2837
}
@@ -2885,6 +2964,8 @@ static int uvc_host_removed(struct usb_device *udev, struct usbh_class_data *cda
2885
2964
return - ENODEV ;
2886
2965
}
2887
2966
2967
+ /*TODO: cancel all of transfers and free all of usb xfer */
2968
+
2888
2969
/* Reset video buffer state */
2889
2970
uvc_dev -> vbuf_offset = 0 ;
2890
2971
uvc_dev -> transfer_count = 0 ;
@@ -3591,7 +3672,14 @@ static int video_usb_uvc_host_set_stream(const struct device *dev, bool enable,
3591
3672
if (enable )
3592
3673
{
3593
3674
if ((vbuf = k_fifo_peek_head (& uvc_dev -> fifo_in )) != NULL ) {
3594
- uvc_host_initiate_transfer (uvc_dev , vbuf );
3675
+ vbuf -> bytesused = 0 ;
3676
+ memset (vbuf -> buffer , 0 , vbuf -> size );
3677
+ uvc_dev -> current_vbuf = vbuf ;
3678
+ while (uvc_dev -> multi_prime_cnt )
3679
+ {
3680
+ uvc_host_initiate_transfer (uvc_dev , vbuf );
3681
+ uvc_dev -> multi_prime_cnt -- ;
3682
+ }
3595
3683
}
3596
3684
}
3597
3685
@@ -3715,4 +3803,3 @@ static DEVICE_API(video, uvc_host_video_api) = {
3715
3803
VIDEO_DEVICE_DEFINE(usb_camera_##n, (void *)DEVICE_DT_INST_GET(n), NULL);
3716
3804
3717
3805
DT_INST_FOREACH_STATUS_OKAY (USBH_VIDEO_DT_DEVICE_DEFINE )
3718
-
0 commit comments